Webpack 4: практические рекомендации по настройке
В сети можно найти множество туториалов по настройке Webpack 4, и каждый из них может чем-то отличаться от другого. Представляем вашему вниманию один из таких туториалов, который можно использовать в качестве примера.
123К открытий124К показов
За перевод благодарим коллектив реакт.рф и автора оригинальной англоязычной версии статьи, Маргариту Образцову.
В Сети есть огромное количество туториалов, поэтому вы, вероятно, видели тысячи различных способов конфигурирования файла Webpack. Каждый из них работает и может служить примером, однако при этом все они немного разные. Почему так? Сам Webpack развивается очень быстро, и многие загрузчики (лоадеры) и плагины должны идти с ним в ногу. Это основная причина, по которой конфиги так отличаются друг от друга: с различными комбинациями одних и тех же инструментов все может как работать, так и не работать.
Позвольте мне выразить свое искреннее мнение: многие люди жалуются на Webpack и трудности в конфигурации. Во многих случаях это так, хотя с моим опытом работы с gulp
и grunt
следует сказать, что вы сталкиваетесь с теми же проблемами несовместимости, когда используете npm-модули.
Webpack сейчас является самым популярным бандлером, у которого недавно произошли серьезные обновления. Они предполагают много нового: нулевую конфигурацию, разумные значения по умолчанию, улучшенную производительность, готовые инструменты оптимизации.
Если вы совершенно незнакомы с Webpack, для начала неплохо будет ознакомиться с документацией. У Webpack она довольно хорошая, с изложением в нескольких частях, поэтому в этом посте я быстро пробегу по основным понятиям.
Нулевая конфигурация: Webpack 4 не требует наличия конфигурационного файла, это одно из новшеств 4-ой версии. Настройка Webpack работает шаг за шагом, поэтому нет необходимости выполнять масштабную конфигурацию с самого начала.
Улучшенная производительность: Webpack 4 — самая быстрая версия Webpack.
Разумные значения по умолчанию: основные понятия Webpack 4 — точка входа, точка вывода, загрузчики (лоадеры) и плагины. Я не буду подробно их описывать, только скажу, что между загрузчиками и плагинами очень расплывчатая разница. Все зависит от того, как автор реализовал библиотеку.
Основные понятия
Точка входа (entry)
Это ваш .js
файл. Вы, возможно, видели несколько конфигураций, в которые включены файлы .scss
или .css
. Это довольно серьезный хак, который может привести ко множеству неожиданных ошибок. Также иногда встречается вход с несколькими .js
файлами. Хотя некоторые плагины позволяют это сделать, скажу, что так делать стоит только тогда, когда вы четко понимаете, зачем вам это нужно.
Точка вывода (output)
Это ваша build/
или dist/
или wateveryounameit/
папка, где будет размещен конечный .js
файл. Это ваш окончательный результат, который впоследствии будет загружен в index.html
.
Загрузчики (loaders)
В основном компилируют или транспилируют ваш код, например, postcss-loader будет проводить ваши стили через разные плагины.
Плагины (plugins)
Играют жизненно важную роль в выводе кода в файлы.
Быстрый старт
Создайте новую директорию и зайдите в нее:
Инициализируем package.json
:
Необходимо загрузить Webpack v4 в качестве модуля и webpack-cli, чтобы запустить его из терминала.
Убедитесь, что установлена именно 4 версия, если же нет, вы можете напрямую выбрать ее в вашем файле package.json
. Далее откройте package.json
и добавьте build-скрипт:
Скорее всего, вылезет предупреждение:
WARNING in configurationThe ‘mode’ option has not been set, webpack will fallback to ‘production’ for this value. Set ‘mode’ option to ‘development’ or ‘production’ to enable defaults for each environment.You can also set it to ‘none’ to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/
Поэтому следующим шагом мы установим флаг режима.
Режимы Webpack 4 (Webpack modes)
Вам необходимо отредактировать скрипт, чтобы в нем появился флаг режима (mode flag):
Это значит, что Webpack ищет папку ./src/
с файлом index.js
. Давайте создадим директорию с .js
файлом, например ./src/index.js
, и добавьте в него такой код:
Теперь запустите dev-скрипт:
Теперь у вас есть директория ./dist/main.js
. Отлично, так как мы знаем, что код скомпилирован. Но что произошло?
Новый Webpack не требует наличия конфигурации, поэтому перед началом использования вам не нужно возиться с webpack.config.js. Из-за этого Webpack вынужден действовать по умолчанию, и он будет искать папку ./src
, а в ней index.js
и выводить в ./dist/main.js
; main.js
— это ваш скомпилированный файл с зависимостями.
Наличие двух конфигурационных файлов — распространенная практика в Webpack, особенно в крупных проектах. Обычно один файл используется для разработки, другой — для продакшена. В Webpack есть два режима: продакшен и разработка. Это избавляет от необходимости создавать два конфигурационных файла (для средних по размеру проектов).
Если вы сейчас проверите файл main.js
, то увидите, что он не изменился.
Примечание В данном примере я буду использовать build-скрипт, поскольку он уже “из коробки” обеспечивает множеством инструментов оптимизации и с этого момента можно свободно их использовать. Основное различие между скриптами build и dev в том, как они выводят файлы. Build создан для продакшен-кода, dev — для разработки: он поддерживает «горячую» замену модулей, webpack-dev-server и многие другие вещи, которые помогают разработчикам.
Вы легко можете переопределять значения по умолчанию в скриптах npm, просто используя флаги:
Это перепишет опции по умолчанию без каких-либо других настроек.
В качестве упражнения попробуйте также флаги:
- флаг наблюдения
watch
для включения режима просмотра. Он будет следить за изменениями вашего файла и компилировать всякий раз при его изменении:
- флаг входа. Работает так же, как и выход, но перезаписывает точку входа.
Транспиляция вашего кода .js
Современный JS-код в основном написан на ES6, а ES6 поддерживается не всеми браузерами. Поэтому вам необходимо транспилировать его. Транспиляция — волшебное слово для перевода ES6 в ES5. Для этого можно использовать babel — наиболее популярный инструмент для транспиляции. Разумеется, он используется не только для ES6, но и для многих инструментов JS, таких как TypeScript, React и т.д.
Далее нужно создать файл конфигурации для babel:
Вставляем туда:
Теперь у нас есть два варианта конфигурации babel-загрузчика:
- Использовать конфигурационный файл
webpack.config.js
. - Использовать
--module-bind
в npm-скриптах.
Технически вы многое можете сделать с новыми флагами, представленными в Webpack, однако для простоты я бы предпочла webpack.config.js
.
Конфигурационный файл
На этом этапе мы создадим webpack.config.js
со следующим содержимым:
Также теперь мы удалим флаги из наших npm-скриптов:
Теперь, когда мы запускаем npm run build
, он должен вывести нам небольшой js-файл в ./dist/main.js
. Если это не происходит, попробуйте переустановить babel-загрузчик.
Наиболее распространенным паттерном Webpack является его использование для компиляции приложения React. Несмотря на это, мы не будем зацикливаться на React’е, поскольку я хочу, чтобы структура была как можно более независимой от фреймворков. Вместо этого я покажу вам, как обрабатывать и создавать конфиги для .html
и .css
.
Импорт HTML и CSS
Для начала в нашей папке ./dist
создадим небольшой файл index.html
.
Как видите, здесь мы импортируем style.css
. Давайте настроим его! Как я уже упомянула, для Webpack у нас есть только одна точка входа. Так куда же мы поставим наш css?
Создаем style.css
в нашей папке ./src
:
Не забываем включить это в js-файл:
В Webpack создайте новое правило для файлов css:
В терминале запустите:
Необходимо использовать ExtractTextPlugin
для компиляции нашего CSS. Как видите, для .css
мы также добавили новое правило.
Краткое описание обычной работы правил:
Примечание Нам необходимо использовать ExtractTextPlugin
, потому что Webpack по умолчанию понимает только формат .js
. ExtractTextPlugin
получает ваш .css
и извлекает его в отдельный css-файл в вашем каталоге ./dist
.
Спойлер: в некоторых статьях пишут, что ExtractTextPlugin
не работает с Webpack 4, но у меня он работал ? Это доказывает мою точку зрения о неоднородном поведении модулей при настройке. Если же у вас этот модуль не работает, вы можете переключиться на MiniCssExtractPlugin
. Далее в этой статье я покажу вам, как настроить и его тоже.
У Webpack, начиная с 4 версии, есть проблемы с этим плагином, поэтому вы можете столкнуться с определенной ошибкой.
Чтобы ее исправить, запустите:
Совет: гуглите вылезающие ошибки и ищите подобные вопросы в GitHub или просто задайте свой вопрос на StackOverflow.
Затем ваш css код должен скомпилироваться в ./dist/style.css
.
На данном этапе dev-зависимости в моем package.json
выглядят так:
Обратите внимание, что иная комбинация может не работать, поскольку даже обновление webpack-cli v2.0.12 до 2.0.13
может «сломать» ее. #justwebpackthings
Теперь ваш style.css
должен выводиться в папку ./dist
:
Поддержка SCSS
Очень часто разрабатываются веб-сайты с SASS и PostCSS. Они весьма полезны. Поэтому мы сперва включим поддержку SASS. Переименуем наш ./src/style.css
и создадим другую папку для хранения файлов .scss
. Теперь необходимо добавить поддержку форматирования .scss
.
Замените style.scss
на ./scss/main.scss
в файле .js
.
Шаблон HTML
Теперь давайте создадим html-шаблон файла. Добавьте файл index.html
в ./src
с точно такой же структурой.
Чтобы использовать этот файл в качестве шаблона, нам понадобится html-плагин.
Добавьте его в ваш вэбпак-файл:
Теперь ваш файл из ./src/index.html
стал шаблоном для конечного файла index.html
.
Чтобы убедиться, что все работает, удалите все файлы из папки ./dist
и саму папку. Затем запустите dev-скрипт:
Вы увидите, что появилась папка ./dist
, и в ней 3 файла: index.html
, style.css
, script.js
.
Кэширование и хеширование
Одна из наиболее распространенных проблем в разработке — реализация кэширования. Очень важно понять, как это работает, ведь вы же хотите, чтобы у ваших пользователей всегда была последняя версия кода.
Поскольку этот пост затрагивает главным образом конфигурацию Webpack, — одним из самых популярных способов решения проблем кеширования является добавление хеш-номера в активные (находящиеся в разработке) файлы (asset), такие как style.css
и script.js
. Об этом можно почитать здесь. Хеширование необходимо, чтобы браузер «научился» запрашивать только измененные файлы.
Webpack 4 имеет встроенные функции, реализованные через chunkhash. Это можно сделать следующим образом:
В файл ./src/index.html
добавьте:
С помощью такого синтаксиса ваш шаблон «научится» использовать хешированные файлы. Это новая фича, реализованная после возникновения этой проблемы.
Мы будем использовать описанный там htmlWebpackPlugin.files.chunks.main
.
Теперь в нашей папке ./dist
есть файл index.html
:
Далее, если мы ничего не изменим в файлах .js
и .css
и запустим:
То увидим, что, независимо от количества запусков, числа в хешах должны быть идентичны в обоих файлах.
Проблемы с хешированием и их решения
Хотя у нас есть рабочий алгоритм, он пока не идеален.
Что, если изменить код в файле .scss
? Окей, меняем .scss
и снова запускаем dev-скрипт. Новый хеш не генерируется.
Что, если мы добавим строки console.log
в наш js-файл вот так:
Если вы снова запустите dev-скрипт, увидите, что в обоих файлах обновлен хеш.
Эта известная проблема, и этот вопрос даже разобран на StackOveflow.
Как теперь это исправить?
Перепробовав немало плагинов, якобы решающих эту проблему, я, наконец, пришла к двум типам решений:
Решение 1
Замените [chukhash]
на простой [hash]
в .css
. Это было одно из решений проблемы. Это похоже на конфликт с webpack 4.3, в котором введена собственная переменная contenthash
. Используйте его вместе с плагином webpack-md5-hash.
Теперь, когда вы вносите изменения в свой файл main.scss
и запускаете скрипт dev
, с новым хешем должен быть сгенерирован только новый style.css
.
Далее протестируем js-файлы. Теперь оба файла меняют хеш.
Решение 2
Все еще могут остаться некоторые конфликты, поэтому теперь попробуем подключить плагин mini-css-extract.
Плагин Mini-CSS
Плагин Mini CSS предназначен для замены плагина extract-text и в дальнейшем для обеспечения лучшей совместимости.
Я реструктурировала свой Webpack-файл, чтобы скомпилировать style.css
с mini-css-extract-plugin, и у меня все работает.
Теперь, когда я редактирую main.scss
, генерируется новый хеш для style.css
. Также, когда я редактирую css, меняются только хеши css, и, когда я редактирую ./src/script.js
, меняются только хеши script.js
!
Интегрирование PostCSS
Чтобы выходной css-файл был безупречным, мы можем добавить наверх PostCSS.
PostCSS предоставляет вам autoprefixer
, cssnano
и другие приятные и удобные штуковины. Буду продвигать то, что использую регулярно. Нам понадобится postcss-загрузчик
. Также по мере необходимости установим autoprefixer
.
Спойлер: для рационального использования PostCSS вам не требуется Webpack, есть довольно приличный плагин post-css-cli, который позволяет вам использовать его в npm-скрипте.
Создайте postcss.config.js
, где вам требуюся соответствующие плагины, вставьте:
Теперь наш webpack.config.js
должен выглядеть так:
Пожалуйста, обратите внимание на порядок плагинов, которые мы используем для .scss
Загрузчик инициализирует плагины, начиная с самого последнего.
Вы можете протестировать autoprefixer, дополнив код в ваших scss-файлах и проверив вывод. Существует также способ исправить выход, указав, какой браузер вы хотите поддерживать в файле .browserslistrc
.
Я бы посоветовала вам PostCSS.parts для изучения плагинов, доступных для PostCSS, например:
Я буду использовать cssnano
для минимизации моего выходного файла и css-mqpacker для упорядочения медиа-запросов. Я также получила несколько подобных сообщений:
При желании можете попробовать cleancss
.
Контроль версий
Ваш package.json
на этом этапе должен иметь следующую структуру:
Очищаем ./dist
Мы можем попробовать импортировать clean-webpack-plugin
, чтобы перед перегенерацией файлов очистить нашу папку ./dist
.
Теперь у нас есть чистенькая и аккуратная конфигурация.
123К открытий124К показов