Оптимизируйте код, используя новую функцию webpackExports

Вы когда-нибудь задумывались, почему сборщики модулей могут «встряхивать» только статический импорт, чтобы уменьшить производственный код? Они не применяют ту же логику включения динамического кода к динамически импортируемым фрагментам. Это вообще возможно? Единственный способ добиться этого до сих пор - обходные пути вручную.

К счастью, разработка в Disney + Hotstar привела к идее более простого решения, которое сейчас существует в виде функции Webpack 5 . Используя последнее дополнение magic comment , webpackExports, мы можем легко получить этот детальный контроль над кодом, особенно если загрузка фрагментов по запросу.

TL;DR

Для многих моих задач во время работы в Disney + Hotstar я хотел загрузить модуль частично, скажем, при запуске приложения, в то время как остальная часть должна быть загружена динамически. в фоновом режиме или при действиях пользователя (которые могут произойти, а могут и не произойти). Эта функция требует разделения в модуле, что требует дополнительных усилий разработчика вручную, тогда как такой инструмент, как Webpack, мог бы позаботиться об этом во время сборки. До сих пор этого не было!

Проблема в том, что мы не можем изменять динамический импорт дерева. Объяснение этому дано в данной статье. Было бы неплохо иметь чистый API, как показано на изображении ниже?

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

import(/* webpackExports: "a" */ 'module')
.then(module => {
  // Only module.a is available
  // No other export is available...
  // Chunk size & network latency are reduced...
})

Читайте дальше, чтобы полностью понять проблему, обходной путь, более простое и лучшее решение Webpack 5, а также подробно ознакомиться с его ограничениями.

Оглавление

Как Webpack оптимизирует ваш код для продакшена

Когда стали популярными такие комплекты модулей, как Rollup и Webpack, стало все более тривиально просто разделить код на разные модули и загрузить их как зависимости. Окончательный комплект будет содержать все модули, необходимые для точки входа.

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

С введением модулей ES6 стало проще встряхивать модули, поскольку их можно анализировать статически. Этого нельзя сказать о CommonJS, поскольку он имеет более динамическую структуру своего require().

В Webpack встряхивание дерева работает только при сборке для производственной среды. Подробнее о Tree Shaking читайте в этой книге и в документации.

Динамический импорт и идея tree shaking таких модулей

Существует спецификация JavaScript под названием динамический импорт для загрузки фрагментов приложения JavaScript во время выполнения, то есть лениво. Это полезно, потому что мы можем использовать факторы времени выполнения для загрузки функций, например, в зависимости от языковых предпочтений пользователя. Мы также можем отложить загрузку модулей по соображениям производительности, то есть не отправлять код до тех пор, пока он не будет использоваться. Есть еще много причин для его использования.

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

Комментарии в приведенном выше разделе не являются частью спецификации, но мы можем использовать их для предоставления именованных фрагментов, определения правил их загрузки и т. Д. Однако есть одна важная часть функциональности, которая отделяет динамически импортируемые модули от статических: динамический импорт по умолчанию не преобразуется в дерево!

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

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

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

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

webpackExports в Webpack 5

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

последний синтаксис выглядит следующим образом:

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

Преимущества:

  • Без ручных задач (без создания новых модулей)
  • Уменьшенные размеры чанков
  • Уменьшает сетевую задержку (меньшая пропускная способность).

Код приложения упрощен. Только Webpack фокусируется на встряхивании деревьев. В целом это увеличивает производительность!

Если вам интересно узнать, как это стало возможным в исходном коде Webpack, посетите мой запрос на вытягивание. Хорошей новостью является то, что webpackExports теперь доступен в Webpack 5, начиная с версии webpack 5.0.0-beta.18.

Я попытался наглядно представить, что происходит с webpackExports:

Ограничения webpackExports

Хотя эта функция облегчает жизнь разработчикам, есть некоторые нюансы, о которых нам нужно знать. В зависимости от того, каким образом мы динамически импортируем экспорт, они могут быть «агрегированы», когда вы их наконец получите.

Предположим, что у нас есть два модуля: Модуль 1 и Модуль 2. Модуль 2 содержит экспорт a и b. Модуль 1 условно импортирует a или b, но никогда оба. Например, в зависимости от выбора пользователя нам нужно либо a, либо b, и пользователь не может выбрать оба! Как вы думаете, что должно содержаться в блоке для модуля 2?

Ответ: Модуль 2 будет содержать как a, так и b, хотя они никогда не могут потребоваться вместе. Кроме того, такое поведение не ограничивается условными предложениями; это также может произойти, когда вы загружаете разные экспортные данные из одного и того же модуля в разные точки внешнего приложения.

Почему это происходит?

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

«Побочный эффект» - это любой эффект, отличный от возвращаемого значения.

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

Следовательно, при создании блока он будет содержать как A, так и B, а также побочные эффекты в одном инкапсулированном модуле (без повторяющихся блоков).

Ограничение вызывает беспокойство?

Нет! Это общее ограничение. Такое бывает даже при статическом импорте. Нам нужно только осторожно осознавать это.

Резюме

В статье говорилось о следующем:

  • Что такое тряска деревьев и как это работает
  • Динамический импорт и почему мы не можем их встряхнуть
  • webpackExports и как мы можем использовать его для оптимизации загружаемого кода по запросу
  • Ограничения webpackExports и таких терминов, как побочные эффекты и живые привязки

Disney + Hotstar собирается перейти на Webpack 5, поскольку он был официально выпущен в этом месяце (то есть в октябре 2020 года). Мы можем использовать это, а также другие интересные функции, такие как более быстрое последующее время сборки за счет постоянного кэширования и объединения модулей для Micro-Frontends. Мы надеемся, что такие обновления впечатлят вас так же, как и нас!

дальнейшее чтение