Установка и настройка Webpack 4 для работы с проектом

(материал без привязки к стэку react/redux/etc)


обложка для статьи

В сети есть миллионы туториалов, поэтому вы, вероятно, видели тысячи различных способов конфигурации файла 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-скрипт:

Скорее всего, вылезет предупреждение:

Режимы Webpack 4 (webpack modes)

Вам необходимо отредактировать скрипт, чтобы в нем появился флаг режима:

Это значит, что webpack ищет папку .src/ с файлом index.js. Для Webpack 4 это действие по умолчанию, так как оно требует нулевой конфигурации.

Давайте создадим директорию с .js файлом, например, ./src/index.js и добавьте в него такой код:

Теперь запустите dev-скрипт:

Теперь у вас есть директория ./dist/main.js. Отлично, так как мы знаем, что код скомпилирован. Но что произошло?

Новый webpack не требует конфигурации, поэтому перед началом использования вам не нужно возиться с webpack.config.js. Из-за этого он вынужден действовать по умолчанию, и он будет искать папку ./src и в ней index.js и выводить в ./dist/main.js main.js — это ваш скомпилированный файл с зависимостями.

Наличие двух конфигурационных файлов — распространенная практика в webpack, особенно в крупных проектах. Обычно один файл используется для разработки, другой — для продакшена. В webpack есть два режима: продакшен и разработка. Это избавляет от необходимости иметь два файла (для средних по размеру проектов).

Если вы уделяете пристальное внимание нашей работе, то вы уже проверили файл main.js и убедились, что он остался неизменным.

В данном примере я буду использовать build-скрипт, поскольку он уже «из коробки» обеспечивает множество инструментов оптимизации и с этого момента способен свободно их использовать. Основное различие между скриптами build и dev в том, как они выводят файлы. Build создан для продакшен-кода. Dev создан для разработки: он поддерживает hot module replacement, webpack-dev-server и многие другие вещи, которые помогают разработчикам.

Вы легко можете переопределять значения по умолчанию в скриптах npm, просто используя флаги:

Такая запись перепишет опции по умолчанию без каких-либо других настроек.

В качестве упражнения попробуйте также флаги:
— флаг наблюдения (watch) для включения режима просмотра. Он будет следить за изменениями вашего файла и компилировать всякий раз при его изменении.

  • флаг входа. Работает так же, как и выход, но перезаписывает точку входа.

Транспиляция вашего кода .js

Современный JS-код в основном написан на ES6, а ES6 поддерживается не всеми браузерами. Поэтому вам необходимо транспилировать его. Transpile — волшебное слово для перевода ES6 в ES5. Для этого можно использовать babel — наиболее популярный инструмент для транспиляции. Разумеется, мы выполняем это не только для ES6, но и для многих инструментов JS, таких как TypeScript, React и т.д.

теперь у нас есть два варианта конфигурации babel-загрузчика:
— используя конфигурационный файл webpack.config.js;
— используя —module-bind в npm скриптах.

Технически вы многое можете сделать с новыми флагами, представленными в webpack, однако для простоты я бы предпочла webpack.config.js.

##Конфигурационный файл

Хотя Webpack рекламирует себя как платформа с нулевой конфигурацией, в основном он применяется к основным значениям по умолчанию, таким как точка входа и вывода.

На этом этапе мы создадим 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:

image

##Поддержка настройки 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:

image

image

Далее, если мы ничего не изменим в файлах .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.

Я бы посоветовала вам https://www.postcss.parts/ для изучения плагинов, доступных для PostCSS, например:
utilities
cssnano
style-lint

Я буду использовать cssnano для минимизации моего выходного файла и css-mqpacker для упорядочения медиа-запросов. Я также получила несколько подобных сообщений:

image

При желании можете попробовать cleancss.

##Контроль версий

Ваш package.json на этом этапе должен иметь следующую структуру:

Чтобы сохранить зависимости, для установки модулей рекомендую использовать **yarn вместо npm. Короче говоря, yarn жестко фиксирует версию пакета, и при переустановке модулей вы сможете избежать многих неожиданных несовместимостей.** (*Npm теперь тоже так умеет, тут я ошиблась)

##Очищаем ./dist

Мы можем попробовать импортировать clean-webpack-plugin, чтобы перед регенерацией файлов очистить нашу папку ./dist.

Теперь, когда у нас есть чистенькая и аккуратная конфигурация, мы будем «жечь»!

В этой статье я предоставила вам свой файл конфигурации и его пошаговую настройку. Примечание: поскольку к моменту, когда вы прочтете это, могут измениться многие npm зависимости, то одна и та же конфигурация у вас может не заработать! Прошу вас указать в комментариях ваши ошибки, чтобы после я могла их исправить. Сегодня 05.04.2018.


Автор оригинального поста — Margarita Obraztsova

Понравилась статья? Поделиться с друзьями:
Комментариев: 7
  1. Антон

    Есть еще одна проблема, ответ на который, пришлось искать опытным путем:

    Исходя из того стейтмента, что ExtractTextPlugin не работает с webpack 4, я заюзал MiniCssExtractPlugin.
    После кучи других настроек и прикручивания различных лоадеров мне понадобился HotModuleReplacement, и поскольку он реализован уже в 4м вебпаке «из коробки» решил воспользоваться им.
    После различных проб и ошибок, оказалось что MiniCssExtractPlugin не работает с ним (или я не понял как это сделать)

    Вернулся к ExtractTextPlugin + еще один пакет. В общем виде все выгдядит так:

    module.exports = {
    module: {
    rules: [{
    test: /\.s?css$/,
    use: [‘css-hot-loader’].concat(ExtractTextPlugin.extract({
    fallback: «style-loader»,
    use: [«css-loader», «postcss-loader», «sass-loader»]
    }))
    },
    devServer: {
    hot: true
    },
    plugins: [
    new ExtractTextPlugin(«styles.css»),
    new webpack.HotModuleReplacementPlugin(),
    ]
    }

  2. Вячеслав

    Спасибо за статью.
    У меня после определённого гугления получилось подружить MiniCssExtractPlugin с «коробочным» HMR (который не react-hot-reload),
    через css-hot-loader, кому интересно, можно посмотреть тут:
    https://github.com/v24dc/js-templates/tree/master/webpack-4-simple
    Единственное но: возникла проблема с content hash, пришлось его отключить. Остальное по статье + webpack-dev-server.

  3. игорь

    спасибо, отличный материал :idea:

  4. Сергей

    // «clean-webpack-plugin»: «^3.0.0»,
    // «webpack»: «^4.39.3»,

    у меня стало чистить dist только после этой корректировки
    const { CleanWebpackPlugin } = require(‘clean-webpack-plugin’);
    ….
    new CleanWebpackPlugin(), //без параметров (похоже он берет их из path)

    источник: https://www.npmjs.com/package/clean-webpack-plugin

    хотелось бы, чтобы вы добавили в статью настройку webpack-dev-server

    насчёт кэширования и хэширования ничего не понял но аккуратно скопировал, работает.:idea:
    также установка и затем комментирование ExtractTextPlugin заметно увеличивает время «дискуссии». и пагубно влияет (имхо) на неокрепший разум webpack-первопроходцев

  5. Сергей

    Ещё немного занудства от меня:

    …Загрузчик использует плагины от начала до конца. (справа-налево — прим.переводчика)
    Означает ли это, что не смотря на то что мы читаем и пишем код слева-направо, то в цепочке вида
    use: [ ‘style-loader’, MiniCssExtractPlugin.loader, ‘css-loader’, ‘postcss-loader’, ‘sass-loader’]
    будет сначала выполняться ‘sass-loader’?
    тогда логичнее было бы написать с конца в начало, слева-направо. (имхо).

    С хешированием разобрался. В общих словах, при постоянном изменении файла стилей и выкладывании страницы в общий доступ, в браузерах клиентов стили кэшируются (сохраняются в память браузера для ускорения загрузки сайта при следующем входе в него) и не обновляются при изменениях внутри файла стилей со стороны разработчика. У меня была такая история (я постоянно просил человека, который просматривал созданную мной страничку удалять историю просмотров браузера, объяснять как это делается, в общем нагружать человека дополнительными действиями) С хешироваными файлами этого можно избежать. Имя файла стилей каждый раз уникальное и кэш браузера таким образом псевдо-игнорируется.

  6. Сергей

    С момента создания config пошли ошибки. Ничего не получилось

    1. Макс

      Вероятно, что-то из зависимостей уже изменилось. К сожалению, давно не проверял этот материал.

Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: