- PVSM.RU - https://www.pvsm.ru -

Frontend для backend девелопера

Сразу хочу оговорится, что данная статья не предназначена для тех, у кого разработка frontend основная деятельность. Целевая аудитория: разработчики backend которым понадобилось срочно прикрутить web UI или просто интересуются новыми областями, ну и возможно fullstack разработчики.

Итак, перейдем к проблеме. Вспоминается статья [1], а также, на просторах Хабара было еще несколько подобных. Представлены они все как шуточные, но как говорится «в каждой шутке есть доля правды», а тут даже и не доля… Но вот в чем вопрос, а действительно ли нужно все это?

Вопрос который я хотел бы поднять, преимущественно о сборке. Именно на этом этапе js-сообщество предлагает неимоверное количество инструментов, необходимость которых совсем не очевидна. Например, сообществом предлагается различные варианты работы с модулями, что имело смысл в свое время, но на данный момент спецификация на import [2]/export [3] поддерживается всеми современными браузерами, и даже недобраузером edge. В силу, оговорённой в начале, задачи, необходимости поддерживать что-либо более старое у нас и нету, так что мы смело останавливаемся на спецификации. А вот то что действительно будет нам необходимо, так это какая либо работа с зависимостями.

Сделаю небольшое отступление, чтобы объяснить выбор технологий, которые будут использоваться в примере для самого frontend’а. Чтобы не копаться в бесчисленном многообразие фреймворков, пойдем от замечательного стандарта [4]. Итак, все становится достаточно просто, виртуального DOM'а там нет, вебкомпоненты есть. На этом можно было бы закончить, но еще js. Если мы решим отделаться чистым [5] js – то придется как-то решать инфраструктурные задачи, избавляться от бойлерплет кода и т.д. Иными словами – городить свой велосипед… Чтобы этого не делать, хотелось бы взять что-нибудь, где все уже сделано и достаточно качественно. Соответственно выбор мой пал на Polymer [6] – фреймворк от Google, которые и пропихнули вебкомпоненты в стандарт.

Чтож, вернемся к сборке. Многие из вас (во всяком случае Java разработчики) привыкли к таким инструментом как maven и gradle, и наверняка успели выяснить, что они прекрасно справляются и с манипуляциями над ресурсами (у maven это конечно немного хуже, но вот у gradle — проблем нет собрать вообще все что угодно). Сообщество же frontend нам предлагает брать npm, для которого нужна nodeJs, но этого не хватит, еще и webpack сверху. А в них еще придется разбираться и ставить каждому разработчику. Эм… Хотелось бы просто выкачать репозиторий, сделать gradlew build и начать работать, так что давайте уж остановимся на привычном gradle.

Совсем без npm мы конечно обойтись не сможем, как минимум, нам нужен репозиторий откуда брать js библиотеки и npm это предоставляет, а вот утилита не обязательна. Можно найти несколько хороших решений вроде этого [7], но они всегда качают nodeJs, и запускают npm таски. Вариант, но мне бы хотелось бы минимизоровать общение с npm до взаимодействия с репозиторием и только. Как решиние было написать свой плагин для gradle. Хоть и писать плагины для gradle достаточно просто, в силу широкого разнообразия возможностей указания версий для npm репозитория, задача несколько усложняется. Благо на это есть понятная документация [8].

Итак, напишим gradle скрипт для загрузки зависимостей. Используется kotlin dsl по той причине, что переписать на groovy dsl достаточно тривиально, а вот наоборот пришлось бы потратить время, если не было ранее опыта.

repositories {
    mavenLocal()
    jcenter()
}

dependencies {
    classpath("com.github.artfable.gradle:gradle-npm-repository-plugin:0.0.3")
}

apply(plugin = "artfable.npm")

configure<GradleNpmRepositoryExtension> {
    output = "$projectDir/src/libs/"
    dependencies = mapOf(
            Pair("@polymer/polymer", "3.0.5"),
            Pair("@polymer/app-layout", "3.0.1"),
            Pair("@polymer/paper-toolbar", "3.0.1"),
            Pair("@polymer/paper-icon-button", "3.0.1"),
            Pair("@polymer/iron-icons", "3.0.1"),
            Pair("@webcomponents/webcomponentsjs", "2.1.3")
    )
}

Данный плагин [9] добавит нам таск npmLoad. Чтобы позволить IDE красиво сгрупировать, определим его в группу

tasks["npmLoad"].group = "frontend"

Отлично, можно попробовать написать код для нашего frontend. Встроенный сервер Intellij по умолчанию скажет вам что Method Not Allowed на попытку подключить скрипты через import. Чтобы это избежать – поставьте чекбокс allow using requests. (в последних версиях работает и без этого).

Settings (pic. 1)

Попробуем теперь запустить, и… Все равно ничего не заработало. Отвалились зависимости внутри компонентов полимера. Дело в том, что многие js библиотеки пушут импорты с расчетом на какой-нибудь транспилер вроде babel. Такой import выглядит например так:

import '@polymer/polymer/polymer-legacy.js';

Что не правильно, так как для браузера путь должен начинаться только с ‘/’, ‘./’ или ‘../’. Кроме того, в таком виде его нельзя брать ни как относительный, ни как абсолютный, так как здесь идет расчет на начало из корня директории с библиотеками. Следовательно такие пути надо исправить, ну и чтобы не делать это самим – можно взять заготовленный плагин [10].

В зависимости

classpath("com.github.artfable.gradle:gradle-js-import-fix-plugin:0.0.1")

apply(plugin = "artfable.js.import.fix")

configure<GradleJsImportFixExtension> {
    directory = "$projectDir/src/libs"
}

Добавится task jsImportFix который приведет все импорты в порядок.

Вот так просто, и без необходимости разбираться с горой новый инструментов, можно собрать фронт. Но давайте еще рассмотрим вопрос со стилями. Откровенно говоря, веб-компоненты позволяют избавится от бойлерплейта, а переменные в css, которые уже в стандарте – открывают множество возможностей, так что необходимости в таких вещах как sass уже больше нет. Но вдруг, например вам очень приглянулся bootstrap [11] и захотелось сделать дизайн на его основе.

Найти какой-нибудь плагин для сборки на этот счет не проблема, в основном, все они за основу берут libsass [12] и есть обертка на java — jsass [13]. Единственная проблема у всех (во всяком случае на момент когда я рассматривал их) в дуплицирование зависимых файлов.

Пример:

Файл a:

@import “b”;
@import “c”;

Файлы _b и _c:

@import “d”;

В результате мы получим в основном файле 2 одинаковых блока из файла _c. Можно достаточно просто исправить, если дописать импортер [14] к jsass, api позволяет. Собственно поэтому я опять со своим решением и здесь [15] (если подобных требований нет, то лучше воспользоваться другим решением).

Добавим в список npm зависимостей

Pair("bootstrap", "4.1.3")

Зависимость на плагин

classpath("com.github.artfable.gradle:gradle-sass-plugin:0.0.1")

apply(plugin = "artfable.sass")

configure<GradleLibsassPluginExtension> {
    group(delegateClosureOf<GradleLibsassPluginGroup> {
        sourceDir = "src/sass"
        outputDir = "src/css"
    } as Closure<Any>)
}

tasks.create("processResources")

Фейковый таск processResources придется создать, если не подключён java-plugin (а он нам здесь и не нужен). Это конечно недоработка, потом обязательно исправлю.

Обратите внимание на то, что полученный css файл нужно подключать не в head, так как внутри компонента он тогда не будет виден, а непосредственно в шаблон самого компонента.

Последним шагом можно немного изменить скрипт, чтобы получить привычную директорию build, с готовым проектом что можно деплоить на прод.

Полный код [16] выложил на github (наверно придется потом мигрировать на gitlab...).

Основная идея надеюсь понятно, а дальше можно добавлять достаточно просто абсолютно все что угодно.

Автор: artfable

Источник [17]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/programmirovanie/307442

Ссылки в тексте:

[1] статья: https://habr.com/ru/post/312022

[2] import: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import

[3] export: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export

[4] стандарта: https://spec.whatwg.org/

[5] чистым: https://www.ecma-international.org/ecma-262/8.0/

[6] Polymer: https://www.polymer-project.org/

[7] этого: https://github.com/srs/gradle-node-plugin

[8] документация: https://docs.npmjs.com/misc/semver

[9] плагин: https://github.com/artfable/gradle-npm-repository-plugin

[10] плагин: https://github.com/artfable/gradle-js-import-fix-plugin

[11] bootstrap: https://getbootstrap.com/

[12] libsass: http://sass-lang.com/libsass

[13] jsass: https://github.com/bit3/jsass

[14] импортер: https://jsass.readthedocs.io/en/latest/importers.html

[15] здесь: https://github.com/artfable/gradle-sass-plugin

[16] Полный код: https://github.com/artfable/frontend-demo

[17] Источник: https://habr.com/ru/post/438584/?utm_source=habrahabr&utm_medium=rss&utm_campaign=438584