Зачем нужно собирать фронтенд

Зачем нужно собирать фронтенд

HTML поддерживает два способа работы с JavaScript. Первый – код добавляется прямо на страницу и второй – код загружается из файла, указанного в теге <script>.

Инлайновые скрипты

Первый способ:

<script>
  document.getElementById('demo').innerHTML = 'Hello JavaScript!';
</script>

Он работает только в самых простых ситуациях. Иногда им пользуются для добавления небольших интерактивных элементов – например, автокомплитов и переключателей табов.

Код в файлах

Современный фронтенд вышел далеко за пределы этих задач. Количество JavaScript кода во многих проектах достигает десяток и сотен тысяч строк кода. Такую массу кода физически невозможно поддерживать внутри HTML. Потому он располагается в отдельных файлах, которых может быть довольно много. Для их подключения используется второй способ:

<!--
Когда браузер встречает тег `<script>` с указанием `src`,
он загружает указанный файл и исполняет его.
Так код получает доступ к содержимому страницы.
-->

<!-- Все определения внутри становятся глобальны и доступны для всех остальных скриптов -->
<script src="/assets/script1.js"></script>
<script src="/assets/script2.js"></script>

Тег <script> был добавлен в HTML очень давно, задолго до появления современной версии языка с модулями. В те времена не существовало Node.js, пакетного менеджера и понятия "зависимости" (dependencies). Весь код писался в одном файле. Даже если файлов было несколько, они никак не были связаны друг с другом. Если попытаться использовать модули вместе с обычным тегом <script>, то браузер выдаст ошибку:

Uncaught SyntaxError: Cannot use import statement outside a module

В теории, код можно писать и без использования системы модулей, но этот способ невероятно трудозатратный и основывается на том, что все определения в коде глобальны (а значит, можно легко что-нибудь сломать, перетерев существующие определения). Придётся руками указывать все существующие файлы и загружать их в HTML, причем в строго определённом порядке. Подобное сейчас встречается только на сайтах, где фронтенд — это jquery с небольшим числом интерактивных элементов.

Отсутствие модулей делает нормальную разработку невозможной. Нельзя работать с зависимостями, нельзя написать тесты, статический анализ кода отсутствует (невозможны переходы по определениям, подсказки).

Модули в браузере

Проблема отсутствия модулей в браузере настолько важная, что в HTML5 ввели поддержку JavaScript-модулей. Достаточно в теге <script> добавить type="module", как браузер начинает их понимать и загружать. Модули понимают практически все современные браузеры.

В HTML:

<script type="module" src="/assets/index.js"></script>

В JavaScript:

// index.js

import app from './app.js';

app();

// app.js

export default () => {
  console.log('Hello from module!');
};

Модули в браузере кардинально всё меняют и позволяют работать с JavaScript так, как это нужно, если бы не одно серьёзное "но". Система модулей в браузере не умеет работать с зависимостями. Если мы решим установить, например, lodash, то попытка его импортировать завершится с ошибкой. Решить эту проблему на уровне браузеров невозможно. Браузер ничего не знает про файловую систему и того, что там происходит.

Uncaught TypeError: Failed to resolve module specifier "lodash".
Relative references must start with either "/", "./", or "../".

Сборщики фронтенда

Эти проблемы полностью решают системы сборки. Кроме загрузки файлов, они решают множество других не менее важных задач. Фронтенд-разработка сильно опирается на различные пре- и пост-процессоры. Например, для современного JavaScript (и TypeScript) и многих фреймворков нужен Babel, который получает на вход исходный код проекта, преобразует его в код понятный браузеру. Только после этого его можно отдавать клиенту.

# Указываем исходную директорию src
# И директорию, в которую положить готовый код
babel src -o dist

То же самое касается CSS. Всё больше разработчиков используют SASS, который нужно транслировать в чистый CSS.

# Указываем исходную директорию stylesheets
# И директорию, в которую положить готовый CSS
sass --update stylesheets dist/stylesheets

Кроме этих задач, сборщики занимаются следующим:

  • Предоставляют единую команду для полной сборки фронтенда, включая все его части
  • Автоматически пересобирают фронтенд во время разработки. Делают это очень быстро, благодаря использованию инкрементальной сборки (собирают только то, что поменялось)
  • Обеспечивают производительность. Минифицируют и сжимают код (в том числе, удаляя неиспользуемый). Разбивают его максимально удобным для кеширования способом
  • Выполняют любые преобразования, например, TypeScript => JavaScript. Позволяют подключать пре- и пост-процессоры, настроить порядок их применения к выбранным файлам

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

Webpack

Одним из первых сборщиков фронтенда стал Webpack. Сейчас он стандарт де-факто в среде фронтенда, хотя существуют и другие решения. Общий принцип работы вебпака такой. В проекте устанавливается сам вебпак и описывается его конфигурация. Эта конфигурация содержит все правила сборки: какие файлы брать, какие обработчики к ним применять и куда складывать результат. На выходе вебпак формирует файл или набор файлов, готовых для загрузки в браузер. Дальше он не участвует, использование этих файлов – задача программиста.

Webpack поставляется как npm-библиотека и устанавливается в проект, обычно, в dev-зависимости, а для работы удобно использовать cli-утилиту:

mkdir webpack-demo
cd webpack-demo
npm init -y
npm i -D webpack webpack-cli

Теперь можно инициализировать новый вебпак-проект, который автоматически создаст все необходимые файлы и конфигурацию одной командой:

npx webpack init --force

Она предложит перезаписать package.json, добавит в проект несколько зависимостей, создаст HTML и JS-файлы, а также создаст конфигурационный файл. Запуск этой же команды без флага --force откроет интерактивный режим, где можно более тонко настроить будущее приложение.

npx webpack init
? Which of the following JS solutions do you want to use? ES6
? Do you want to use webpack-dev-server? Yes
? Do you want to simplify the creation of HTML files for your bundle? Yes
? Do you want to add PWA support? No
? Which of the following CSS solutions do you want to use? none
? Do you like to install prettier to format generated configuration? No
? Pick a package manager: npm
[webpack-cli] ℹ INFO  Initialising project...
 conflict package.json
? Overwrite package.json? overwrite
    force package.json
   create src/index.js
   create README.md
   create index.html
   create webpack.config.js
   create .babelrc

# вывод об установке библиотек

[webpack-cli] ⚠ Generated configuration may not be properly formatted as prettier is not installed.
[webpack-cli] Project has been initialised with webpack!

Проект готов и теперь его можно запустить:

npx webpack serve

Эта команда соберёт приложение в режиме разработки, откроет браузер и отобразит содержимое HTML-файла, а в консоль выведется сообщение из src/index.js.

Запущенное в браузере Webpack-приложение

Конфигурационный файл webpack.config.js будет содержать несколько плагинов, необходимых для работы с HTML. Всё готово, чтобы написать своё первое фронтенд-приложение, используя Webpack!

Лучший способ продолжить с ним работу — это читать официальную документацию и изучить Webpack Boilerplate, созданный Хекслетом.

Исходный код (github)
Кирилл Мокевнин
comments powered by Disqus