Команда разработчиков Webpack этот раз изрядно потрудилась над новым поколением популярного сборщика модулей (бандлера) — webpack 4.
Репозиторий с используемым кодом здесь.
Webpack 4 как сборщик модулей с нулевой конфигурацией
Никто не спорит: у него есть мощные плюсы, большое количество возможностей и настроек, однако головной болью является файл конфигурации.
Написание конфига не составляет проблемы для средних и больших проектов, без этого им трудно существовать. Тем не менее, небольшие проекты это может раздражать, особенно если хочется создать приложение-игрушку.
Шон и команда webpack улучшили жизнь всем нам: webpack 4 больше не требует файла конфигурации по умолчанию!
Что ж, протестируем.
Создайте новую директорию и перейдите туда:
mkdir webpack-4-quickstart && cd $_
Инициализируйте package.json:
npm init -y
Теперь пускаем в бой webpack 4 (Версия сейчас находится в стадии beta, поэтому нужно добавить next):
npm i webpack@next --save-dev
Добавим webpack-cli, живущий своей жизнью в отдельном пакете:
npm i webpack-cli --save-dev
Открываем package.json и прописываем скрипт сборки:
"scripts": {
"build": "webpack"
}
Сохраните файл, закройте. Запустите:
npm run build
Что же случилось?
ERROR in Entry module not found: Error: Can't resolve './src' in '~/webpack-4-quickstart'
Webpack 4 ищет входную точку приложения ./src! Если не знаете, почему так получилось, то опишу вкратце: входная точка — это файл, с которого webpack начинает сборку. В ранних версиях нужно было объявить ее напрямую в webpack.config.js.
Но начиная с 4-й версии вам не нужно указывать входную точку. Она будет взята из ./src/index.js по умолчанию!
Проверим. Создайте ./src/index.js:
console.log(`Можно я тут просто постою?`);
Снова запустите сборку:
npm run build
Вы получите файл ~/webpack-4-quickstart/dist/main.js.
Неужели нам не нужно задавать и точку выхода тоже? Именно! Ни точку входа, ни выхода. Тем более, не нужен файл конфигурации.
Я знаю, что для большинства это неудивительно: сила webpack в разделении кода. Но поверьте: ноль конфигурации ускоряет разработку в разы.
Режимы production и development
Очень часто можно встретить разделения конфига на несколько файлов.
Типичный проект может иметь:
- Конфигурацию для разработки (development), с webpack-dev-server и прочими игрушками разработчиков.
- Конфигурация для продакшена с UglifyJSPlugin, source maps и другим.
Пока крупные проекты продолжают использовать разделение конфигов, мы с webpack 4 сделаем все одной строкой.
Как так? Встречайте режимы production и development.
Если вы обратите внимание на вывод npm run build, то увидите красивую ошибку:
Опция ‘mode’ (режим) не была задана. Включите режим в ‘development’ или ‘production’, чтобы применить настройки по умолчанию.
Что это значит? Будем разбираться. Откройте package.json и допишите объект скриптов, как показано ниже:
"scripts": {
"dev": "webpack --mode development",
"build": "webpack --mode production"
}
И теперь попробуем:
npm run dev
Взглянем на ./dist/main.js. Что вы видите? Да, я знаю, скучный бандл… не уменьшен. А если:
npm run build
Что теперь? Файл сборки был уменьшен. Да! Режим ‘production’ использует все виды оптимизации самостоятельно. И там не только минимизация.
С другой стороны режим разработчика (development mode) оптимизирует скорость приложения и ничего больше.
Таким образом, с 4-м webpack’ом вы можете менять всю сборку одной строкой. Просто добавьте флажок --mode и получите результат совершенно безболезненно.
Нравятся ли вам нововведения? Чего ожидаете от webpack в будущем? Пишите в комментариях.
Спасибо за внимание.
Комментарии (37)
BuccapuoH
29.01.2018 22:51Список изменений впечатляет, жаль только, что с ExtractTextPlugin они не сильно спешат. Для веба это просто маст хэв, а текущая стабильная версия с новым webpack работать не может — API для плагинов сменили кардинально.
Фича с указанием sideEffects выглядит весьма многообещающе. Очень надеюсь, что она наконец починит Tree shaking.
VanishMax Автор
29.01.2018 23:08В оригинале для продакшена написано: Production mode enables all sorts of optimizations out of the box. Including minification, scope hoisting, tree-shaking and more.
Не проверял, но хочется верить, что все работает
k12th
30.01.2018 12:56Вообще непонятно, почему ExtractTextPlugin не встроен в webpack из коробки. Я кое-как смирился с
import './style.scss'
, но деплоить стили в виде гигантского строкового литерала в JS все ещё не готов. До сих пор хорошей практикой остается вставлять стили вhead
, а скрипты перед</body>
.
Но, может быть, нужда в нём отпадёт за счет того что 4.x будет поддерживать типы модулей html и css, то есть их не надо будет заворачивать в JS? Посмотрим
crazymax11
30.01.2018 19:25Если вас беспокоит style-loader как fallback для асинхронных чанков, то посмотрите в сторону ExtractCssPlugin. Он выносит весь css из всех чанков.
Не уверен правда, что работает с webpack 4. Но на webpack 3 полёт нормальный.k12th
30.01.2018 19:31Меня беспокоит, что такой фичи нету из коробки и надо танцевать с бубном. А менять один плагин на другой (кстати, я что-то так и не нагуглил ExtractCssPlugin) смысла особо не вижу — оба надо отдельно ставить и конфигурировать.
crazymax11
30.01.2018 19:43Немного название неправильно написал, вот он.
Ну конфигурация сверх лоадеров там всего несколько строчек
- вызов
new Plugin({filename: 'mask'});
pluginInstance.extract(loadersChain)
Да, отсутствие хорошей поддержки css из под коробки, конечно, немного смущает, тут не поспоришь.
k12th
30.01.2018 19:51Спасибо.
Что-то это по конфигу не сильно отличается… А в чем преимущество, что-то я туплю? Делает code split для css?
crazymax11
30.01.2018 20:22+1Этот плагин по умолчанию для каждого асинхронного чанка создает свой css чанк. ExtractTextPlugin же выносит текст только из entry чанка.
Давайте рассмотрим на примере.
У вас есть чанки
- app.js — entry point
- common.js — получаемый из commonChunksPlugin
- mainPage.js — асинхронный чанк с функционалом главной страницы
В случае использования ExtractTextPlugin вы получите на выходе
- app.css — css entry поинта, которого будет не очень много
- common.js, mainpage.js — содержат стили внутри js'a через style-loader
В общем-то, в такой схеме ExtractTextPlugin не выглядит особо полезным.
ExtractCssChunksPlugin вообще не имеет опции fallback т.к. она ему не нужна, с помощью этого плагина вы получите следующую структуру:
- app.css — все тоже самое
- common.css — все общие стили
- mainPage.css — стили главной страницы
ExtractCssChunksPlugin — это ИМХО то, как должен работать ExtractTextPlugin по умолчанию.
Минусы этого плагина:
- Возможно не поддерживает webpack 4 (не проверял ещё)
- Дефолтное значение filename может мешать, уж много плагин на себя берёт этим значением, мог бы полагаться на то, что указано в секции output
- Он полагается на ExtractTextPlugin, и это видно в логах. Это само по себе не проблема. Если правильно помню структуру проекта, то проблема в том, что ExtractTextPlugin просто скопипащен (ctrl+c ctrl+v) внутрь ExtractCssChunks. Это, во первых, ужасно. Во вторых, можете забыть о получении фиксов\улучшений ExtractTextPlugin. Поэтому если встретите баг, который был исправлен в ExtractTextPlugin, вероятно он не будет исправлен в ExtractCssChunks.
Но мы используем ExtractCssChunks в продакшне и полёт пока ровный
justboris
31.01.2018 20:13Да, отсутствие хорошей поддержки css из под коробки, конечно, немного смущает, тут не поспоришь.
В прошлом году нам обещали улучшенную поддержку:
https://medium.com/webpack/the-new-css-workflow-step-1-79583bd107d7Но что-то с тех пор апдейтов не видно
k12th
01.02.2018 00:57We add a new module type to webpack: Stylesheet (next to Javascript)
Обещают в 4.x.
- вызов
yuzi
30.01.2018 16:33Собственно, потому стабильный релиз и состоится через месяц, чтобы разработчики плагинов могли подготовиться к интеграции с 4-й версией Webpack-а.
Finesse
30.01.2018 03:48Как насчёт обратной совместимости? В своё время, когда изучал Webpack, я столкнулся с проблемой: актуальной версией Webpack была 2, которая обратно-несовместимостима с версией 1 (плагины, написанные для версии 1 не работали с Webpack 2 и наоборот), а большая часть плагинов была написана для версии 1; приходилось ультимативно решать, какую версию Webpack использовать, и лучшим выбором являлась версия 1, потому что для неё было намного больше плагинов.
pmcode
30.01.2018 06:58Не люблю черные ящики и котов в мешке, поэтому если в точке входа по умолчанию еще есть какие-то плюсы, то система сборки, которая использует «все виды оптимизации самостоятельно» вызывает разрадражение.
С другой стороны, если они подробно опишут в документации какие именно настройки применяются для каждого режима по умолчанию, и поддержат их точечное изменение (а заодно и то, чтобы можно было где-то глобально пложить собственные дефолты для каждого режима), то это реально поможет сократить простыню, которую приходится писать в конфиг…
tehSLy
30.01.2018 09:52То есть киллер фича 4й версии это -2 строчки в конфиге?
VanishMax Автор
30.01.2018 09:58Разве это не прекрасно?!
staticlab
30.01.2018 11:04А пропагандировалось как zero configuration
alix_ginger
30.01.2018 13:07Это, как я понял, последние 2 строчки в конфиге, которые были обязательными раньше. То есть, в результате да — zero configuration.
zim32
30.01.2018 15:39А что насчет http 2? Не отпадает ли надобность в вебпаке как таковом? Не судите строго просто прочитал где-то что с приходом http 2 сборка всего в один файл становится не нужной
k12th
30.01.2018 15:46Все равно нужен будет live/hot-reload, препроцессоры и минификация для продакшена (для мобильников это всё еще важно) — хотя возможно что этим будет заниматься уже не вебпак.
zim32
30.01.2018 15:48Ждем возвращение gulp?
k12th
30.01.2018 15:49Эту стюардессу не то что пора закопать, ей вообще не надо было рождаться:)
zim32
30.01.2018 15:51Хотя для сборки разного рода библиотек вебпак действительно прекрасен
k12th
30.01.2018 15:58Неплох. Но они даже сами писали, что для сборки именно библиотек rollup лучше. Да и конфиги у rollup все-таки поприятнее.
crazymax11
30.01.2018 19:22+2Весьма популярное заблуждение. Http2 не решает проблему, которую решает бандлинг.
Давайте представим ситуацию.
У вас есть точка входа, которая импортит класс приложения, который импортит еще модуль и так далее.
Думаю, вы без труда найдете в своем коде, например, 8 уровней импортов.
entry => application => rootComponent => component => anotherComponent => someLibrary => lodash.
Если отказаться от сборки исходников в один\несколько файлов, то возникает следующая ситуация.
- Браузер получает ваш entry point, узнает что ему нужен application
- Получает application, узнает, что нужен rootComponent
- и так далее до 8 уровня
Каждый шаг для браузера — это отдельный запрос со всеми вытекающими. http2 позволяет переиспользовать соединение, однако задержка между вами и пользователем, как ни крути, останется.
Если предположить, что задержка 50мс, то только 400мс уйдет на то, чтобы спросить у вас файлы (не учитывая скачивание, парсинг и всё такое). Если пользователь, не дай бог, с мобильного интернета, то там уже совсем другие цифры.
Решение у этой проблемы есть — сразу говорить пользователю, какие файлы ему понадобятся. Вместо того, чтобы собирать один\несколько файлов, нам теперь нужно строить граф зависимостей, чтобы оптимизировать отправку. Можно и из булки сделать троллейбус, но зачем? Воркфлоу без потерь не упрощается.
Ну и бонусом, бандлинг позволяет очень хорошо оптимизировать код (минификация, дедупликация, tree shaking, лучше гзипуется, легче пересылается по сети)
zim32
30.01.2018 20:25Ну по идее эту проблему решает http2 push. А как бонус не надо грузить ненужный код, и возможность кешировать ресурсы более рационально.
crazymax11
30.01.2018 20:44+2Ну я про то и говорил.
Чтобы сделать http2 push вам нужно знать, что пушить.
Для того, чтобы знать, что пушить, вам нужен граф зависимостей, чтобы резолвнуть те модули, которые запросит пользователь. Не сказать, чтобы это сильно проще, но это решение, да. Также тут на хабре есть [статья](https://habrahabr.ru/company/badoo/blog/331216/), про то что пока не нужно использовать server push, браузеры его поддерживают по разному и нетривиально его сделать правильно. А если сделать неправильно, то пользователю будет плохо
Ну и есть еще подводные камни, вот пара статей по этому поводу:
* www.contentful.com/blog/2017/04/04/es6-modules-support-lands-in-browsers-is-it-time-to-rethink-bundling
* engineering.khanacademy.org/posts/js-packaging-http2.htm
Aquahawk
30.01.2018 21:19каждый раз когда возникает желание посмотреть на http2 вспоминайте этот доклад www.youtube.com/watch?v=whFhyHysYYg
Aquahawk
31.01.2018 12:01в целом ненавижу когда вместо гибких настроек и хорошей документации к ним с преднастроенным дефолным конфигом пытаются делать zeroConfig. Потом тебе надо что-то поменять и привет пол часа гугления, а иногда и дольше.
Есть хороший принцип, простое — просто, сложное — возможно. Но на самом деле он не совсем полон, хорошо когда ещё и переход от простого к сложному происходит без переписывания кода или смены api. Или как в данном случае разумным считаю иметь преднастроенный дефолтный конфиг, с разделами где вписаны все настройки по умолчанию. И конфиг побит на разделы, типа base options, advanced options и expert. И тогда всё просто и понятно. И проще гуглить поведение каждой настройки.
Akuma
А разве смысл webpack.config.js только в задании точек входа/выхода? :)
VanishMax Автор
В данной статье описываются новые фичи. В дебри вебпака залезать не было смысла
alix_ginger
В переопределении параметров по умолчанию. Теперь у точки входа и выхода есть значения по умолчанию, и переопределять их не обязательно