Всем привет! На этот раз на повестке дня перевод статьи Valentino Gagliardi «Webpack 4 tutorial: All You Need to Know, from 0 Conf to Production Mode».

image

Команда разработчиков 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


image

Очень часто можно встретить разделения конфига на несколько файлов.

Типичный проект может иметь:

  • Конфигурацию для разработки (development), с webpack-dev-server и прочими игрушками разработчиков.
  • Конфигурация для продакшена с UglifyJSPlugin, source maps и другим.

Пока крупные проекты продолжают использовать разделение конфигов, мы с webpack 4 сделаем все одной строкой.

Как так? Встречайте режимы production и development.

Если вы обратите внимание на вывод npm run build, то увидите красивую ошибку:

image
Опция ‘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)


  1. Akuma
    29.01.2018 22:50

    А разве смысл webpack.config.js только в задании точек входа/выхода? :)


    1. VanishMax Автор
      29.01.2018 23:10

      В данной статье описываются новые фичи. В дебри вебпака залезать не было смысла


    1. alix_ginger
      30.01.2018 10:20

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


  1. BuccapuoH
    29.01.2018 22:51

    Список изменений впечатляет, жаль только, что с ExtractTextPlugin они не сильно спешат. Для веба это просто маст хэв, а текущая стабильная версия с новым webpack работать не может — API для плагинов сменили кардинально.


    Фича с указанием sideEffects выглядит весьма многообещающе. Очень надеюсь, что она наконец починит Tree shaking.


    1. 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.
      Не проверял, но хочется верить, что все работает


    1. k12th
      30.01.2018 12:56

      Вообще непонятно, почему ExtractTextPlugin не встроен в webpack из коробки. Я кое-как смирился с import './style.scss', но деплоить стили в виде гигантского строкового литерала в JS все ещё не готов. До сих пор хорошей практикой остается вставлять стили в head, а скрипты перед </body>.


      Но, может быть, нужда в нём отпадёт за счет того что 4.x будет поддерживать типы модулей html и css, то есть их не надо будет заворачивать в JS? Посмотрим


      1. crazymax11
        30.01.2018 19:25

        Если вас беспокоит style-loader как fallback для асинхронных чанков, то посмотрите в сторону ExtractCssPlugin. Он выносит весь css из всех чанков.
        Не уверен правда, что работает с webpack 4. Но на webpack 3 полёт нормальный.


        1. k12th
          30.01.2018 19:31

          Меня беспокоит, что такой фичи нету из коробки и надо танцевать с бубном. А менять один плагин на другой (кстати, я что-то так и не нагуглил ExtractCssPlugin) смысла особо не вижу — оба надо отдельно ставить и конфигурировать.


          1. crazymax11
            30.01.2018 19:43

            Немного название неправильно написал, вот он.


            Ну конфигурация сверх лоадеров там всего несколько строчек


            • вызов new Plugin({filename: 'mask'});
            • pluginInstance.extract(loadersChain)

            Да, отсутствие хорошей поддержки css из под коробки, конечно, немного смущает, тут не поспоришь.


            1. k12th
              30.01.2018 19:51

              Спасибо.


              Что-то это по конфигу не сильно отличается… А в чем преимущество, что-то я туплю? Делает code split для css?


              1. 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 в продакшне и полёт пока ровный


                1. k12th
                  30.01.2018 21:06

                  Большое спасибо за подробное объяснение!


            1. justboris
              31.01.2018 20:13

              Да, отсутствие хорошей поддержки css из под коробки, конечно, немного смущает, тут не поспоришь.
              В прошлом году нам обещали улучшенную поддержку:
              https://medium.com/webpack/the-new-css-workflow-step-1-79583bd107d7

              Но что-то с тех пор апдейтов не видно


              1. k12th
                01.02.2018 00:57

                We add a new module type to webpack: Stylesheet (next to Javascript)

                Обещают в 4.x.


    1. yuzi
      30.01.2018 16:33

      Собственно, потому стабильный релиз и состоится через месяц, чтобы разработчики плагинов могли подготовиться к интеграции с 4-й версией Webpack-а.


  1. staticlab
    29.01.2018 22:52

    А что насчёт интеграции с бабелем?


    1. VanishMax Автор
      29.01.2018 23:06

      В этом плане ничего не изменилось — можно брать старый конфиг и смело юзать


  1. Dreyk
    30.01.2018 00:39

    все ок, только sourcemaps — это не карты сайта :)


  1. Finesse
    30.01.2018 03:48

    Как насчёт обратной совместимости? В своё время, когда изучал Webpack, я столкнулся с проблемой: актуальной версией Webpack была 2, которая обратно-несовместимостима с версией 1 (плагины, написанные для версии 1 не работали с Webpack 2 и наоборот), а большая часть плагинов была написана для версии 1; приходилось ультимативно решать, какую версию Webpack использовать, и лучшим выбором являлась версия 1, потому что для неё было намного больше плагинов.


  1. pmcode
    30.01.2018 06:58

    Не люблю черные ящики и котов в мешке, поэтому если в точке входа по умолчанию еще есть какие-то плюсы, то система сборки, которая использует «все виды оптимизации самостоятельно» вызывает разрадражение.

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


  1. tehSLy
    30.01.2018 09:52

    То есть киллер фича 4й версии это -2 строчки в конфиге?


    1. VanishMax Автор
      30.01.2018 09:58

      Разве это не прекрасно?!


      1. staticlab
        30.01.2018 11:04

        А пропагандировалось как zero configuration


        1. alix_ginger
          30.01.2018 13:07

          Это, как я понял, последние 2 строчки в конфиге, которые были обязательными раньше. То есть, в результате да — zero configuration.


  1. Methos
    30.01.2018 13:16

    Детский сад


  1. zim32
    30.01.2018 15:39

    А что насчет http 2? Не отпадает ли надобность в вебпаке как таковом? Не судите строго просто прочитал где-то что с приходом http 2 сборка всего в один файл становится не нужной


    1. k12th
      30.01.2018 15:46

      Все равно нужен будет live/hot-reload, препроцессоры и минификация для продакшена (для мобильников это всё еще важно) — хотя возможно что этим будет заниматься уже не вебпак.


      1. zim32
        30.01.2018 15:48

        Ждем возвращение gulp?


        1. k12th
          30.01.2018 15:49

          Эту стюардессу не то что пора закопать, ей вообще не надо было рождаться:)


          1. zim32
            30.01.2018 15:51

            Хотя для сборки разного рода библиотек вебпак действительно прекрасен


            1. k12th
              30.01.2018 15:58

              Неплох. Но они даже сами писали, что для сборки именно библиотек rollup лучше. Да и конфиги у rollup все-таки поприятнее.


    1. 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, лучше гзипуется, легче пересылается по сети)


      1. zim32
        30.01.2018 20:25

        Ну по идее эту проблему решает http2 push. А как бонус не надо грузить ненужный код, и возможность кешировать ресурсы более рационально.


        1. 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


        1. staticlab
          30.01.2018 20:44

          -


    1. Aquahawk
      30.01.2018 21:19

      каждый раз когда возникает желание посмотреть на http2 вспоминайте этот доклад www.youtube.com/watch?v=whFhyHysYYg


  1. Aquahawk
    31.01.2018 12:01

    в целом ненавижу когда вместо гибких настроек и хорошей документации к ним с преднастроенным дефолным конфигом пытаются делать zeroConfig. Потом тебе надо что-то поменять и привет пол часа гугления, а иногда и дольше.
    Есть хороший принцип, простое — просто, сложное — возможно. Но на самом деле он не совсем полон, хорошо когда ещё и переход от простого к сложному происходит без переписывания кода или смены api. Или как в данном случае разумным считаю иметь преднастроенный дефолтный конфиг, с разделами где вписаны все настройки по умолчанию. И конфиг побит на разделы, типа base options, advanced options и expert. И тогда всё просто и понятно. И проще гуглить поведение каждой настройки.