Обзор:

Webpack — это проект с открытым исходным кодом, он обслуживает множество вариантов использования для сборок внешнего интерфейса, включая объединение, стандартизацию, минимизацию, автоматизацию задач и многое другое, благодаря ядру webpack и расширяемой системе плагинов. С таким огромным потенциальным влиянием для такого проекта, как веб-пакет, очень сложно время от времени вносить критические изменения, они должны планировать внесение критических изменений вместе в один основной выпуск из-за неудобств, которые в противном случае это причинит разработчикам. После двух лет разработки webpack недавно выпустил крупное обновление, то есть webpack 5.

Мы активно используем webpack для всех наших настроек сборки в smallcase, и в рамках нашей инженерной практики мы решили, что сейчас самое подходящее время для обновления до webpack 5.

Webpack 5 поставляется с множеством изменений и оптимизаций, которые невозможно описать в одном сообщении в блоге. с которыми мы столкнулись и перспективы на будущее.

Что дает веб-пакет 5:

Отказ от ответственности. Большое спасибо https://malcolmlaing.medium.com/ за его статью на https://frontend-digest.com/whats-new-in-webpack- 5-ef619bb74fae для приведенной ниже простой для понимания классификации функций.

Эта новая версия концентрируется на пяти ключевых областях.

Более быстрые сборки с постоянным кэшированием

Сборщик модулей теперь предлагает опциональный кеш файловой системы, что, в свою очередь, сокращает время сборки.

Меньшие размеры пакетов

Были внесены улучшения в встряхивание дерева (также известное как устранение мертвого кода). В то время как предыдущие версии webpack могли удалять неиспользуемый код, версия 5 пошла еще дальше. Webpack теперь может удалять код внутри модулей, что приводит к еще меньшему размеру пакетов. Чтобы узнать больше обо всех функциях оптимизации webpack 5, ознакомьтесь с официальной документацией.

Лучшее долгосрочное кэширование

В Webpack 5 изменения, внесенные в код, не затрагивающие свернутую версию (например, комментарии или имена переменных), не приводят к аннулированию кеша. Это означает, что пользователи смогут дольше пользоваться преимуществами кэширования.

Критические изменения сейчас, чтобы позволить дальнейшие улучшения позже

Некоторые изменения, внесенные в эту версию, не окажут заметного влияния на производительность вашего приложения сегодня. Вместо этого они предназначены для добавления новых функций и улучшений в более поздние версии webpack 5.

Эти будущие функции включают использование импорта http(s) в качестве внешних модулей. Это поможет в разработке микрофронтендов. Чтобы узнать больше об этих новых и интересных функциях, ознакомьтесь с официальной документацией здесь.

Еще одно серьезное изменение — увеличение минимальной версии Node.JS с 6 до 10.13.0. Прекращение поддержки старых версий Node.JS позволит команде упростить свой код и удалить обходные пути для поддержки этих старых версий.

Webpack 5 также предоставляет новую опцию конфигурации экспериментов с поддержкой WebAssembly, Async Web Assembly, Top Level Await и выводом вашего пакета в виде модуля (ранее это было возможно только при объединении).

Федерация модулей

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

Наша мотивация для обновления:

В smallcase, в рамках нашей инженерной практики, мы внимательно следим за инструментами и зависимостями в наших проектах и ​​раз в два квартала или около того анализируем, для каких зависимостей доступны более новые версии, а для каких нет. устаревают, и мы по возможности обновляемся до более новой версии. Мы верим в последовательное обновление наших зависимостей и использование новых функций в наших кодовых базах.

Ранее в smallcase мы использовали webpack 4.3.x и решили перейти на webpack 5, ознакомившись с преимуществами этой версии. Ниже приведены несколько преимуществ, которые нас порадовали, и вы также можете обратиться к документации по веб-пакету для более глубокого понимания:

Более быстрые сборки

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

Долгосрочное кэширование.

На данный момент мы зависим от хэша каждой сборки, сгенерированного из веб-пакета, что означает, что мы не используем преимущества долгосрочного кэширования. Мы планировали перейти к хэшу для каждого файла, чтобы оптимизировать долгосрочное кэширование, поэтому это улучшение будет полезным.

Улучшенное встряхивание дерева

У нас есть собственная библиотека компонентов, которая является зависимостью для наших потребителей, и у нас были некоторые проблемы с встряхиванием дерева по умолчанию в прошлом, что привело к изменениям в том, как мы организуем кодовую базу библиотеки компонентов, чтобы потребительский веб-пакет мог правильно встряхнуть дерево. . Это улучшение потенциально могло бы помочь в этом.

Федерация модулей

У нас уже есть существующий вариант использования, в котором у нас есть эта настройка для настройки микроинтерфейса времени сборки, и нам пришлось сделать некоторые обходные пути до объединения модулей. Мы очень рады использовать webpack в будущем для этого.

Модули активов вместо загрузчиков URL/файлов

Ожидание лучших размеров пакетов с этим по умолчанию.

Наша настройка веб-пакета:

Прежде чем обсуждать подход к миграции, было бы полезно настроить контекст и предоставить обзор того, как мы в настоящее время используем веб-пакет в нашей настройке. Мы используем webpack не только для процесса сборки, но и для многих других целей. Мы используем довольно характерную настройку веб-пакета. Мы используем Post CSS и CSS Modules в нашей кодовой базе, и у нас есть загрузчики для запуска этой установки. У нас есть специфичные для среды конфигурации веб-пакетов, которые объединяются с общей конфигурацией для создания окончательной конфигурации во время сборки.

Общие возможности webpack, которые мы используем:

Встраивание активов
Мы используем это для встраивания изображений в качестве URL-адреса данных, которые меньше определенного размера, а изображения большего размера могут быть получены из сети. Это помогает нам поддерживать баланс между размером фрагмента и сетевыми вызовами.

Псевдоним
Мы называем папку src ~ в конфигурации нашего веб-пакета, чтобы упростить разработчикам импорт из папки src вместо громоздкого относительного импорта.

Разбиение на фрагменты для улучшения размера пакетов
Мы полагаемся на разделение по частям по умолчанию с помощью плагина разделенных блоков, а также имеем настройку для блоков конкретных поставщиков, общего блока и других блоков с явными именами.

Наши специальные возможности веб-пакета, которые мы используем:

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

Разрешение зависимостей с символическими ссылками
У нас есть библиотека компонентов под названием smallcase-components, которая находится в отдельной кодовой базе. Мы реализуем общие повторно используемые компоненты в этой кодовой базе и используем их в потребительских кодовых базах. Пока компоненты разрабатываются, нам нужно иногда тестировать их, потребляя их на потребителе локально, мы делаем это с помощью символической ссылки на кодовую базу компонентов, используя resolve.symlinks: false. Это требуется только для того, чтобы убедиться, что зависимости для пакетов с символическими ссылками взяты из правильного места.

Настройка тестового идентификатора
У нас есть настройка, в которой мы добавляем атрибут data-test-id ко многим элементам, чтобы помочь QA с автоматическим тестированием. Эти тестовые идентификаторы не являются жестко закодированными и не должны быть легко угадываемыми, поэтому мы используем сопоставление, при котором разработчикам нужно только указать семантические имена для этих элементов в коде, а во время сборки веб-пакет заменит эти семантические имена случайными хэшами. Затем Webpack создаст файл json с семантическим именем для отображения хэша, который мы передаем QA. QA также может использовать семантические имена в своей кодовой базе и заменять их сгенерированными хэшами во время выполнения.

Открыть манифест во время выполнения
Для конкретной оптимизации производительности, когда мы хотели контролировать предварительную загрузку определенных фрагментов на основе некоторой информации, доступной только во время выполнения, нам нужно было открыть webpack manifest для получения сгенерированного файла. имена во время выполнения, а затем предварительно загружать их с помощью динамически генерируемых тегов link rel=”preload” во время выполнения. Мы написали собственный подключаемый модуль веб-пакета поверх уже доступного подключаемого модуля манифеста веб-пакета, который подключается к выходным данным подключаемого модуля манифеста веб-пакета и подключаемого модуля веб-пакета html, чтобы предоставить манифест среде выполнения, вставив его в объект окна в сгенерированном HTML.

Плагин копирования для микроинтерфейса времени сборки
У нас есть настройка микроинтерфейса времени сборки, в которой мы используем другое реагирующее приложение в одной части нашего приложения. Другое реагирующее приложение имеет собственную настройку веб-пакета и генерирует свои фрагменты веб-пакета в своей собственной папке сборки. Затем это публикуется в npm, и, используя его в нашем приложении, мы должны убедиться, что наш веб-пакет может найти эти фрагменты во время выполнения. Этого не может произойти, если чанки находятся внутри node_modules, поэтому нам нужно скопировать эти сгенерированные чанки вместе с нашими чанками, чтобы они были доступны во время выполнения для нашего веб-пакета.

Время сборки Многопользовательская среда с использованием загрузчика строк и глобальных флагов функцийУ нас есть многопользовательская кодовая база внешнего интерфейса, где мы создаем отдельные сборки для каждого клиента. Большинство настроек арендатора управляются с помощью глобальных переменных веб-пакета, используемых в качестве флагов функций. У нас также есть настройка, в которой нам нужно импортировать вещи из конкретных папок арендатора, что включается с помощью string-replace-loader, который заменяет заполнитель имени арендатора в импорте фактическим именем арендатора во время сборки.

Подход:

Поскольку мы уже использовали webpack v4, мы начали с шагов, упомянутых в руководстве по переходу с webpack 4 на webpack 5.

  • мы уже были на node >= 10, который совместим с webpack 5
  • обновил webpack 4, webpack cli и плагины/загрузчики до последней версии, поддерживающей v4. Это было необходимо для того, чтобы мы могли просмотреть все предупреждения об устаревании и исправить их, потому что веб-пакет 5 собирается удалить все то, что уже устарело в версии 4.

Следующим шагом было обновление до Webpack 5, убедитесь, что все зависимости обновлены до версий, совместимых с Webpack 5.

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

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

В основном мы следовали официальному руководству по миграции веб-пакетов.

Изменения, сделанные для миграции:

  • Все изменения, связанные с postcss, перенесены на postcss.config.js, чтобы очистить наши конфигурации веб-пакетов.
  • во время миграции мы поняли, что у нас нет явного browserlist, поэтому сборки веб-пакетов создавались на основе предустановленной конфигурации среды Babel. Мы добавили явный .browserlistrc для оптимизации сборки
  • Обновлена ​​конфигурация пользовательского веб-пакета Storybook для соответствия API Storybook6.
  • Обновлен синтаксис историй в соответствии с storybook 6 изменениями.
  • Рефакторинг нашей конфигурации веб-пакета для конкретной среды, чтобы извлечь больше вещей в webpack.common.js
  • Как обсуждалось выше, у нас есть собственный плагин для веб-пакетов под названием ExposeManifestPlugin. Этот плагин отвечает за замену текста-заполнителя в index.html манифестом веб-пакета, который представляет собой карту JSON всех файлов, сгенерированных веб-пакетом. В предыдущей реализации мы подключились к emit hook компиляции веб-пакета, чтобы получить html, сгенерированный из html-webpack-plugin, а также к хуку emit плагина манифеста, чтобы получить файл json, сгенерированный из плагина манифеста. В новой реализации ресурсы нельзя изменять ни в каком другом хуке, кроме хука processAssets, поэтому нам нужно было подключиться к хуку processAssets и обновить html с помощью сгенерированного json. С этим изменением нам не нужно использовать какой-либо хук из подключаемого модуля манифеста, потому что мы подключаемся к ресурсам на этапе, где доступны все ресурсы, созданные из любого предыдущего плагина.
    Соответствующие ссылки :
    - https://github.com/webpack/webpack/pull/10876
    - Автор плагина использует один и тот же хук для чтения всех ресурсов и создания json
    — Webpack теперь заменяет исходники в Compilation.assets вариантами SizeOnlySource, чтобы уменьшить использование памяти.
    https://github.com/webpack/webpack/issues/11425
  • Команда webpack-dev-server заменена на webpack serve.
  • Переменные ENV теперь можно передавать в webpack как — env VAR=”FOOBAR” instead of env.VAR=”FOOBAR”
  • импорт для плагина webpack-manifest изменился на:
const { WebpackManifestPlugin } = require(‘webpack-manifest-plugin’);
  • использование [hash] в конфигурациях веб-пакетов, таких как [hash].bundle.js, устарело, заменено на [contenthash]. Это включает долгосрочное кэширование по умолчанию.
  • Использование обозначения загрузчика 'style-loader!css-loader' устарело и заменено на
    [{loader: ‘style-loader’}, {loader: ‘css-loader’}]
    - Этот синтаксис обычно используется для импорта файлов css из node_modules при использовании сторонних библиотек, которые не должны проходить через ваш обычный конвейер сборки css. Ранее мы использовали это для импорта css из react-vis (библиотека диаграмм) и react-table, но мы уже исправили это, чтобы сделать это в нашей конфигурации веб-пакета, вместо того, чтобы делать это во время импорта. С этим изменением нам нужно было только исправить синтаксис загрузчика в нашем правиле веб-пакета, поскольку мы использовали старый синтаксис загрузчика в конфигурации веб-пакета.
  • Сценарий сборки, который мы использовали в Jenkins для развертывания проекта, использовал переменные среды, синтаксис которых изменился, как обсуждалось ранее. Поэтому нам нужно было обновить скрипты сборки, чтобы они поддерживали новый синтаксис переменных среды. например ENV.BROKER=”xyz” теперь станет ENV BROKER=“xyz” (. заменяется пробелом). Это изменение также требовалось в наших сценариях npm, которые запускали webpack с некоторыми переменными env по умолчанию.
  • Удалены file-loader, url-loader в пользу веб-пакета модули активов
  • Обновлена ​​конфигурация SplitChunks согласно веб-пакету 5. Из параметров конфигурации были удалены два ключа, а именно maxSize и automaticNameMaxLength.
    — Мы все равно использовали maxSize = 0, значение по умолчанию, поэтому мы его удалили.
    - automaticNameMaxLength было удалено из веб-пакета 5. В любом случае, оно было введено, чтобы помочь разработчикам ограничить количество символов в именах сгенерированных файлов чанков, но из-за этого ограничения оно влияло на кеширование, как упоминалось здесь. Согласно коду, теперь по умолчанию используется максимальное значение 100.
  • Обновлено название инструмента разработки для cheap-module-eval-source-map на eval-cheap-module-source-map.

Обновленные пакеты:

  • webpack
  • webpack-cli
  • webpack-manifest-plugin
    - Мы использовали это, чтобы предоставить коду сгенерированный манифест во время выполнения для предварительной загрузки некоторых пакетов для оптимизации производительности.
  • string-replace-loader
    - У нас есть кодовая база с несколькими арендаторами, в рамках этой настройки мы используем ее для замены имени арендатора в URL-адресах импорта файлов.
  • html-webpack-plugin
  • copy-webpack-plugin
    — мы используем это для копирования некоторых файлов из другой папки в конечную папку dist, чтобы они были доступны по правильному пути во время выполнения. Помимо прочего, это то, что мы также используем для настройки микроинтерфейса во время сборки, который, как мы надеемся, будет заменен федерацией модулей.
  • clean-webpack-plugin
  • webpack-bundle-analyzer
  • terser-webpack-plugin
    - Нам нужно было настроить некоторые параметры в плагине terser, плагин terser, используемый Webpack внутри, не позволяет передавать параметры настройки, поэтому нам нужно переопределить его новым экземпляром извне.. https:// webpack.js.org/plugins/terser-webpack-plugin/

Связанный с загрузчиком Postcss:

Мы используем загрузчик postcss в веб-пакете вместе с множеством плагинов. Вся настройка postcss была обновлена ​​до postcss v8, и все плагины должны были быть обновлены, чтобы быть совместимыми с postcss v8 и использовать их версии, совместимые с webpack 5.

  • postcss
  • postcss-custom-media
  • postcss-custom-properties
  • postcss-flexbugs-fixes
  • postcss-import
  • postcss-loader
  • postcss-mixins
  • postcss-nested
  • Postcss-simple-vars

Связанный со сборником рассказов:

Мы используем пользовательскую конфигурацию веб-пакета в сборнике рассказов, который заимствует из нашей основной конфигурации веб-пакета, поэтому, если мы обновлялись до веб-пакета 5 в основной конфигурации, требовалось обновить сборник рассказов с версии 5 до версии 6, чтобы перевести сборник рассказов на использование веб-пакета 5.

  • storybook/addon-a11y
  • storybook/addon-actions
  • storybook/addon-controls
  • storybook/addon-links
  • storybook/addon-viewport
  • storybook/addons
  • storybook/builder-webpack5
  • storybook/manager-webpack5
  • storybook/react

Удаленные пакеты

  • compression-webpack-plugin (Мы больше не использовали этот пакет)
  • Storybook-zeplin (мы больше не использовали этот пакет)
  • Dotenv-webpack (мы больше не использовали этот пакет)
  • Url-loader
    - Этот вариант использования теперь покрывается загрузчиком ресурсов.
  • Postcss-hexrgba
    — этот пакет не был обновлен для правильного использования изменений webpack 5, поэтому нам пришлось его удалить. Подробнее в разделе проблем.

Возникшие проблемы

Плагин HexRGBA:

Поскольку мы удалили postcss-hexrgba из-за его несовместимости с postcss8, и он не поддерживается активно, в настоящее время нет плагина для преобразования шестнадцатеричных значений в RGBA.

Чтобы исправить это, у нас был PR в smallcase-components, который устраняет зависимость этого плагина, напрямую используя значения RGB вместо шестнадцатеричных значений.

Нам пришлось обновить значения в платформе Broker, которые использовали плагин hexrgba для цветов, все вхождения hexrgba были заменены на rgba.

Это вызвало проблему в нашей сборке (а также в репозитории sc-dot-com при переходе на webpack5), из-за которой сборка останавливалась после определенного прогресса и зависала без каких-либо предупреждений или ошибок, Ширшенду Бхоумик при дальнейшей отладке выяснилось, что это проблема с пакетом postcss-custom-properties. Они выпустили свой v11 с примечаниями к выпуску, в которых упоминалось, что теперь они поддерживают postcss8, поскольку эта проблема исправлялась, было обнаружено, что они выпустили v12 с теми же примечаниями к выпуску и написали (основной выпуск) с ним .
Обновление этого пакета до версии 12 решило проблему.

Обновление сборника рассказов:

Были проблемы, которые блокировали миграцию storybook6 с webpack5.

  • Используя v 6.3.x с 6.4.x для надстроек сборника рассказов, при обновлении всего до последней версии мы получили один пакет @storybook/addon-docs на 6.4.x, а все остальные надстройки были на 6.3.x. Не было никакой документации, указывающей, что это может потенциально сломать что-то. Решение для этого было найдено, когда я обратился к команде сборника рассказов на их канале в разногласиях, объяснив нашу проблему и поделившись версиями пакетов, которые мы использовали, и их технический менеджер предложил перенести все пакеты на 6.3.x, что в конечном итоге и стало исправлением.
  • Вторая проблема заключалась в том, что документы не генерировались с помощью storybook6 и webpack5, причиной этого было переопределение плагина babel-plugin-react-docgen из-за добавления нашей пользовательской конфигурации webpack в сборник рассказов. Исправление этой проблемы заключалось в добавлении явного кода, чтобы убедиться, что это правило всегда присутствует в нашем последнем плагине webpack.

Модули активов:

Раньше мы использовали url-loader и file-loader для управления встроенными активами. В этой настройке у нас был установлен предел для max asset size, обрабатываемых загрузчиком URL. При этом только те активы, которые находились под лимитом, были отправлены с пакетом и оптимизировали размер нашего пакета в webpack4.

Первоначально, когда мы заменили url-loader и т. д., чтобы вместо этого использовать модули ресурсов из webpack5, была огромная разница в размере пакета при запуске bundle-analyzer, при дальнейшем рассмотрении было обнаружено, что причиной этого было то, что ресурсы не были встроены в bundle, и это произошло из-за отсутствия параметра maxSize в модулях активов.

Мы добавили параметр maxSize в наш код, и это восстановило нормальную работу пакета + ресурсы.

Файлы карты и лицензия не создаются:

Была замечена проблема после миграции webpack5, заключающаяся в том, что файлы карты и лицензии вообще не генерировались. При дальнейшем расследовании было обнаружено, что в clean-webpack-plugin требуется обновление с версии 3.x.x. В v4, поскольку они официально представили поддержку webpack 5 в v4. После обновления пакета проблема была решена.

УСТАРЕВШИЕ РЕКОМЕНДАЦИИ:

storybook/addon-knobs устарел в пользу storybook/addon-controls, миграция требует приличного количества изменений с историями, поэтому не является частью этого PR.

Планы на будущее:

  • Несмотря на то, что мы обновились до webpack 5, нам еще предстоит реализовать функции, которые послужили мотивом для этого обновления, кроме общих преимуществ. Поэтому мы собирали их по одному.
  • Полифилы Node Js были удалены, и полифилы, специфичные для внешнего интерфейса, должны быть явно включены. Это не влияет на нас, поскольку наше приложение является SPA, и мы не используем webpack для какой-либо сборки node js, и мы используем babel для наших полифилов внешнего интерфейса, но нам нужно изучить это подробнее.
  • Пересмотрите кэширование и древовидную структуру в целом.
  • Webpack стал немного громоздким, поэтому в будущем мы будем изучать/оценивать и другие сборщики.
  • Мы используем волшебные комментарии для создания именованных чанков, кажется, в веб-пакете 5 есть способ указать именованные чанки (chundIds: «named»), поэтому эти волшебные комментарии не потребуются. Также предлагается использовать chunkIds: «hash» в производстве для лучшего долгосрочного кэширования, поэтому нам нужно изучить это.
  • Изучите систему плагинов и различные хуки и этапы обработки ресурсов, чтобы убедиться, что наш плагин манифеста раскрытия работает должным образом.
  • В настоящее время мы используем css-loader 3.x.x. При попытке обновления до версии 4.x или более поздней он не совместим с модулями babel-plugin-react-css. обновлен, чтобы его можно было использовать с css-loader, но автор неактивен с 2019 года. Хэш, сгенерированный css-loader, и хеш, сгенерированный модулями babel-plugin-react-css, не совпадают, из-за чего не было css работающий. Подробнее здесь.
    - Здесь есть форк того же пакета, который обновлен с изменениями, необходимыми для поддержки последнего css-загрузчика, но проблема с использованием форка связана с потенциальной неактивностью автора в будущем. Например, в будущем, если css-loader снова изменит свой хэш, форк может устареть и сломать все, если мы захотим обновиться до последней версии css-loader.

Использованная литература:

Большое спасибо Гаураву Гупте за рецензирование и вклад в этот блог!