Webpack 4: обзор обновлений

8 min read

На днях вышла новая версия популярной системы сборки Webpack 4.0. Команда опубликовала большой Changelog и восторженный пост на Medium с описанием обновлений системы.

К текущему моменту не все изменения описаны в официальной документации. В этой заметке — обзор новых возможностей и проблем, с которыми вы можете столкнуться при обновлении.

Шон Ларкин, ведущий разработчик Webpack, Angular Cli, Microsoft Edge

Режимы сборки

Добавлен обязательный параметр --mode, определяющий один их трех режимов сборки: production, development и none, от которых зависят различные оптимизации и внешний вид бандла. Режим production оптимизирован под уменьшение размера сборки, а development — уменьшение времени сборки. В режиме none все оптимизации отключены. 

А еще можно сконфигурировать собственный режим, отключив или включив определенные оптимизации с помощью опций optimization.* в конфиге. Доступные настройки отсутствуют в документации, зато их описал основатель Webpack Тобиас Копперс в блоге на Medium.

Тобиас Копперс

import() CommonJS-модулей

Больше нельзя подключать CommonJS-модули через import(). То есть либо используйте require, либо пишите модули по стандарту ES6 modules.

CommonJS

const a = require("./a") module.exports = { a, b: 2 }

ESM

import a from "./a" export default { a, b: 2 }

Удаленные плагины

Минификация

Отдельным пунктом про UglifyJsPlugin. Он, наконец, научился поддерживать ES6 модули, но в базовой конфигурации он больше не нужен — для минификации сборки используется опция optimization.minimize = true, которая по умолчанию включена в режиме production. Не используемый код (dead code) Webpack теперь тоже вырезает без помощи UglifyJs.

Плагин или функцию, которая будет заниматься минификацией, можно переопределить в optimization.minimizer

Типы модулей

Изначально Webpack был ориентирован именно на сборку JavaScript-файлов. Но впоследствии его стали применять для сборки всего на свете: CSS, HTML, картинок и тд, в процессе испытывая боль с конфигурацией точек входа, лоадерами и плагинами. Теперь появились Module Types:

Типы модулей определяются либо автоматически по расширению файла, либо задаются с помощью свойства module.rules[].type в конфиге.

module: { rules: [ { test: /\.js$/, type: 'javascript/esm', use: { loader: 'eslint-loader', } }, ] }

По словам разработчиков, введение типов позволит им в следующих обновлениях Webpack добавить возможность создавать CSS, HTML и другие сборки, без точки входа на JavaScript.

Webpack-cli вынесен в отдельный проект

Это значит, что чтобы запускать сборку из командной строки или через менеджер пакетов, нужно установить webpack-cli вручную.

npm install --save-dev webpack-cli

или 

yarn add --dev webpack-cli

Поддержка WebAssembly

Появилась возможность подключать WebAssembly-модули через import или require. Другими словами, в сборку можно подключать бинарные скрипты C++, C, Rust и другие, но для этого потребуются соответствующие лоадеры.

Сами модули WebAssembly тоже могут «реквайрить» другие .js и .wasm модули.

Поддержка sideEffects: false в package.json

Свойство sideEffects в файле package.json в значении false сообщает, что пакет не содержит действий, изменяющих состояние внешних переменных, DOM-узлов и тд.

Он упрощает встроенный Tree Shaking и оптимизирует сборку переиспользуемых частей кода.

sideEffects можно переопределить для каждого модуля в свойстве module.rules

Магические комментарии к динамическим импортам

В Webpack конструкции вида 

modulesList.forEach( module => require('src/' + module) );

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

Возможность создавать динамические импорты реализуется с помощью ContextReplacementPlugin, который заранее включает в сборку файлы по заданным паттернам. Еще один вариант динамических импортов — асинхронная подгрузка модулей через Code Splitting.

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

import( /* webpackExclude: "system.js" */ 'module' );

Больше информации при сборке

Работа с переменными окружения

Если раньше вы передавали чувствительные данные, хранящиеся в переменных окружения с помощью DefinePlugin, то теперь это можно сделать «из коробки» с помощью optimization.nodeEnv: true, тогда они автоматически попадут в proccess.env.NODE_ENV.*

Этой возможности нет в Changelog, но она есть в исходниках. И, видимо, в определенный момент появится в документации. 

Source Maps

Опция devtools теперь поддерживает свойства include, test и exclude.

В режиме development по умолчанию генерируются source maps типа eval. Для более детальной настройки source maps разработчики рекомендуют использовать SourceMapDevToolPlugin.

Дефолтная конфигурация

Для простейшей сборки больше не требуется webpack.config.js, тк ряд обязательных параметров получил значения по умолчанию.

Если вы занимаетесь разработкой лоадеров или плагинов для Webpack, обратите внимание на список изменений в API без обратной совместимости.

Troubleshooting

Если вы решили обновить версию Webpack, то начать лучше с удаления всех модулей и плагинов (а лучше — всей локальной папки node_modules), после чего установить новый Webpack и затем — поставить плагины заново. Это сэкономит время на решении проблем с совместимостью и обновлением зависимостей.

Дальше разбор некоторых частых ошибок.

The CLI moved into a separate package: webpack-cli. Please install 'webpack-cli' in addition to webpack itself to use the CLI. -> When using npm: npm install webpack-cli -D -> When using yarn: yarn add webpack-cli -D

— установить webpack-cli

Error: webpack.optimize.UglifyJsPlugin has been removed, please use config.optimization.minimize instead.

— отключить плагин, заменить на optimization.minimize: true 

WARNING in configuration The 'mode' option has not been set. Set 'mode' option to 'development' or 'production' to enable defaults for this environment.

— передать --mode production (или development) при запуске скрипта webpack

npm WARN extract-text-webpack-plugin@2.1.2 requires a peer of webpack@^2.2.0 but none was installed.

— избавиться от ExtractTextWebpackPlugin (разработчики за полтора месяца тестирования беты Webpack 4 не предоставили обновления), либо, потратив N-времени в гугле, найти и установить нестабильную альфу.

npm i --save-dev extract-text-webpack-plugin@v4.0.0-alpha.0

Зачем это все

Шон Ларкин, технарь Microsoft Edge и один из ведущих разработчиков Webpack и Angular Cli,  провел опрос в твиттере с предложением сравнить скорость сборки до и после обновления на 4 версию. По его словам, прирост составил до 98%

Что дальше

А дальше последуют патч-версии (читай, багфиксы), одна из которых вышла пока писался этот материал. Существенный прирост в скорости сборки во многом был обусловлен рефакторингом ядра, который позволит реализовать старые featue-реквесты и свежие идеи на обновленном API. Шон уже озвучил ряд нововведений, которые появятся либо в минорных обновлениях четвертой версии, либо, вероятнее всего, в Webpack 5.

Шон завершает публикацию словами о Ренессансе JavaScript и «переосмыслении» миссии Webpack. 

А мы продолжаем работать.