Из рук в руки, возьмите вас за использование webpack4 в разумной позе (ниже)

внешний интерфейс Webpack
Из рук в руки, возьмите вас за использование webpack4 в разумной позе (ниже)

Автор статьи изТехнологическая группа Wall Street News - цветочные брюки

Перед прочтением этой статьи рекомендуется прочитать вводное руководство по веб-пакету.

В этой статье используется webpack4 (ниже) для практического опыта, который в основном разделен на две части:

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

Стратегия субподряда по умолчанию

Самое большое изменение в webpack 4 заключается в том, что он упразднен.CommonsChunkPluginпредставилoptimization.splitChunks.

веб-пакет 4Code SplittingЕго самая большая особенность заключается в том, что его легко настроить, если вашmodeдаproduction, то автоматически запустится webpack 4Code Splitting.

Следующее будетvue-element-adminНапример. онлайнbundle-report

Как показано на рисунке выше, ничего не настраивая, webpack 4 будет разумно подпаковывать код для вас. Файлы, от которых зависит файл записи, упакованы вapp.js, сторонние пакеты размером более 30 КБ, например:echarts,xlsx,dropzoneи т.п. упаковываются отдельно в отдельные связки.

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

  • Является ли новый чанк общим или модулем из node_modules
  • Размер нового фрагмента больше 30 КБ перед сжатием.
  • Количество одновременных запросов на загрузку чанков по запросу меньше или равно 5
  • Количество одновременных запросов при первоначальной загрузке страницы меньше или равно 3

Но есть небольшие компоненты, как показано выше:vue-count-toВ несжатом состоянии он весит всего 5 КБ, и хотя он разделяется двумя страницами, webpack 4 по умолчанию упакует его с кодом этих лениво загруженных страниц, а не разделит на отдельный пакет. (Хоть он и общий, но ведь объем не больше 30кб)

Вы можете подумать, что есть проблема со стратегией веб-пакета по умолчанию.Один из моих компонентов покрыт несколькими страницами.Вы упаковываете этот компонент на каждую страницу.Не будет ли повторяться, чтобы упаковать этот компонент много раз? просто возьмиvue-count-toНапример, вы можете поместить общий两次以上Компоненты или код извлекаются отдельно и упаковываются в бандл, но не стоит забыватьvue-count-toВ несжатом виде это всего 5 КБ, а после сжатия gizp может быть всего около 1,5 КБ.Чтобы поделиться кодом 1,5 КБ, вы должны потратить лишнее время на потерю http-запроса, что не стоит потерь. Я лично считаю, что текущие правила упаковки webpack по умолчанию являются более разумной стратегией.

Но в некоторых случаях эти правила могут показаться не очень разумными. Например у меня фон управления, большая часть его страниц это формы и таблицы, я использую сторонний табличный компонент, он нужен почти каждой странице в фоне, но его объем всего 15кб, отдельной распаковки у него нет Стандартно он вот так упаковывается в комплект каждой страницы, что является пустой тратой ресурсов. В этом случае рекомендуется извлекать компоненты, которые могут быть общими для большинства страниц, по отдельности и объединять их в один.component-vendor.jsпакет (описан ниже).

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

Оптимизация стратегии субподряда

просто возьмиvue-element-admin, он основан наElement-UIфон администратора, поэтому он будет использовать, например,echarts,xlsx,dropzoneand other third-party plug-ins, and because it is the management background, it will also write many common components, such as various packaged search query components, shared business modules, etc. If you follow the default unpacking rules, the result Not настолько совершенен.

Как показано на первом рисунке, посколькуelement-uiсуществуетentryФайл записи импортируется и используется на большом количестве страниц, поэтому по умолчанию он будет упакован вapp.jsсреди. Это нецелесообразно, потому чтоapp.jsтакже содержит вашrouter 路由声明,store 全局状态,utils 公共函数,icons 图标И так далее по этим глобальным общим вещам.

но кромеelement-ui, а остальные вещи часто модифицируются в ходе обычной разработки.Например, я добавил глобальную функцию function,utils文件изменится, или если я изменю путь маршрута,router文件изменения, которые приведут кapp.jsХэш меняется:app.1.js => app.2.js. Но из-заelement-uiа такжеvue/reactи т.д. тоже запакованы в них, и хотя вы их не меняете, их кеш тоже последуетapp.xxx.jsИзмените и потерпите неудачу, что очень неразумно. Поэтому нам нужно оптимизировать стратегию кэширования самостоятельно.

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

Мы переделываем наш код в соответствии с приведенной выше таблицей, и он становится таким.

  • Чанк-библиотеки базовой библиотеки классов

Для нашего проекта необходимы некоторые базовые библиотеки классов, такие какvue+vue-router+vuex+axiosЭто стандартные семейные корзины, они не часто обновляются, но нужны каждой странице. (В него также могут быть помещены некоторые глобально общие, небольшие сторонние библиотеки: такие как nprogress, js-cookie, clipboard и т. д.)

  • библиотека компонентов пользовательского интерфейса

Теоретически библиотеку UI-компонентов тоже можно поместить в libs, но причина ее вынесения здесь: она действительно большая, будь тоElement-UIещеAnt DesignСжатый gizp может иметь размер около 200 КБ, что может быть намного больше, чем все библиотеки в библиотеках вместе взятых, а частота обновления библиотеки компонентов пользовательского интерфейса относительно выше, чем у библиотек. Время от времени мы обновляем библиотеку компонентов пользовательского интерфейса, чтобы исправить некоторые существующие ошибки или использовать некоторые из ее новых функций. Поэтому рекомендуется разделить библиотеку UI-компонентов на отдельный пакет.

  • Пользовательский компонент/функция

Достояния здесь в основном делятся нанеобходимоа такжеНесущественный.

Обязательные компоненты — это те компоненты или функции в проекте, которые должны быть загружены для правильной работы. Например, ваша таблица маршрутизации, глобальное состояние, такие компоненты, как глобальная боковая панель/верхний/нижний колонтитул, пользовательские значки Svg и т. д. На самом деле это то, от чего вы зависите в файле ввода, и по умолчанию они будут упакованы вapp.jsсередина.

Необязательные компоненты — это модули, которые используются большинством страниц, но не импортируются в запись файла записи. Например: фон управления, вы инкапсулируете множество компонентов select или table, поскольку их размер не очень велик, они по умолчанию будут упакованы в чанк каждой ленивой страницы, что приведет к большому количеству отходов. У вас есть десять страниц, ссылающихся на него, и пакет будет переупакован десять раз. Следовательно, те компоненты, которые являются широко распространенными, должны быть упакованы отдельно вchunk-commons.

Однако все еще зависит от конкретной ситуации. В общем, вы также можете использовать теНеобязательные компоненты\функцииТакже введен в запись файла записи, иТребуемые компоненты\функцииПакет вместеapp.jsВ этом нет никакой проблемы.

  • низкочастотные компоненты

низкочастотные компоненты и общие компоненты вышеchunk-commonsСамая большая разница заключается в том, что они используются только в некоторых конкретных бизнес-сценариях, таких как редакторы форматированного текста,js-xlsxИнтерфейсная библиотека обработки Excel и т. д. Как правило, эти библиотеки являются сторонними и имеют размер более 30 КБ, поэтому по умолчанию webpack 4 будет упакован в отдельный пакет. Никакой специальной обработки не требуется. Если он меньше 30 КБ, он будет упакован в пакет страниц, который его использует.

  • Бизнес-код

Эта часть представляет собой бизнес-код, который мы обычно пишем. Как правило, они упакованы в соответствии с разделением страниц, например, в vue используйтеОтложенная загрузка маршрутаспособ загрузить страницуcomponent: () => import('./Foo.vue')webpack по умолчанию объединит его в отдельный пакет.

Полный код конфигурации:

splitChunks: {
  chunks: "all",
  cacheGroups: {
    libs: {
      name: "chunk-libs",
      test: /[\\/]node_modules[\\/]/,
      priority: 10,
      chunks: "initial" // 只打包初始时依赖的第三方
    },
    elementUI: {
      name: "chunk-elementUI", // 单独将 elementUI 拆包
      priority: 20, // 权重要大于 libs 和 app 不然会被打包进 libs 或者 app
      test: /[\\/]node_modules[\\/]element-ui[\\/]/
    },
    commons: {
      name: "chunk-commons",
      test: resolve("src/components"), // 可自定义拓展你的规则
      minChunks: 2, // 最小共用次数
      priority: 5,
      reuseExistingChunk: true
    }
  }
};

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

Это позволит максимально использовать кеш браузера. Конечно, эта оптимизация по-прежнему должна варьироваться от проекта к проекту. Например, общие компоненты на рисунке вышеchunk-commons, он может быть запакован и может оказаться очень большим и содержать много компонентов, но он нужен не каждой странице или большинству страниц. Вполне возможно, что происходит такая ситуация: Странице А нужно толькоchunk-commonsВнутри компонента A а скачать целикомchunk-commons.js, в это время вам нужно подумать, разумна ли текущая стратегия распаковки и нужна ли онаchunk-commons? Или упаковать эти компоненты в свои пакеты? или настроить егоminChunks: 2(минимальное количество акций)? Или изменить его правила распаковки?

// 或者你可以把策略改为只提取那些你注册在全局的组件。

- test: resolve("src/components")
+ test: resolve("src/components/global_components") //你注册全局组件的目录

игра

По сути, оптимизация — этоиграПроцесс увеличения размера бандла или б?Ускорить первую загрузку или увеличить использование кеша? Но нужно помнить об одном, при распаковке не гонитесь за слишком большой детализацией, все идет в комплекте отдельно, иначе может понадобиться загрузить не один десяток страниц на одной странице..jsфайл, если вы еще неHTTP/2В случае , блокировка запросов по-прежнему очевидна (ограничена количеством одновременных запросов браузера). Поэтому полного решения стратегии загрузки ресурсов в этом предложении нет, нужно найти наиболее подходящую стратегию распаковки в сочетании с собственным проектом.

такие как поддержкаHTTP/2случае вы можете использоватьwebpack4.15.0добавленmaxSize, он может преобразовать вашchunkсуществуетminSizeБолее разумное разделение в диапазоне, чтобы вы могли лучше использоватьHTTP/2для длительного кэширования (вHTTP/2В случае , стратегия кэширования не такая, как раньше).


Long term caching

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

  • Для html файлов: не открывать кеш, ставить html на свой сервер, закрывать кеш сервера
  • Для статических js, css, картинок и других файлов: включить cdn и кеширование, загрузить статические ресурсы в сервис-провайдер cdn, мы можем включить долгосрочное кеширование ресурсов, потому что путь каждого ресурса уникален, поэтому он не вызовет ресурсы быть Покрытие для обеспечения стабильности онлайн-доступа пользователей.
  • Каждый раз, когда выходит обновление, статические ресурсы (js, css, img) сначала загружаются в сервис cdn, а затем загружается html-файл, что не только обеспечивает нормальный доступ старых пользователей, но и позволяет новым пользователи, чтобы увидеть новые страницы.

Статьи по ТемеКак разработать и внедрить интерфейсный код в крупной компании?

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

На самом деле webpack 4 проделал очень хорошую работу по постоянному кэшированию, но все же есть некоторые недостатки.Мы обсудим эту проблему с этих аспектов ниже.

  • RuntimeChunk(manifest)
  • Module vs Chunk
  • HashedModuleIdsPlugin
  • NamedChunksPlugin

RuntimeChunk(manifest)

webpack 4 предоставляет runtimeChunk, который позволяет нам легко извлекатьmanifest, ранее нам нужно было настроить так

new webpack.optimize.CommonsChunkPlugin({
  name: "manifest",
  minChunks: Infinity
});

Теперь требуется только одна строка конфигурации

{
  runtimeChunk: true;
}

Его эффект заключается в том, чтобы включитьchunks 映射关系的 listодин изapp.jsИзвлеките из него, потому что идентификатор каждого фрагмента в основном основан на хеше контента, поэтому каждое изменение, которое вы делаете, будет влиять на него.Если вы его не извлекаете, он равенapp.jsОн меняется каждый раз. Кэш недействителен.

После отдельного извлечения runtimeChunk каждый пакет будет генерироватьruntimeChunk.xxx.js. (Имя по умолчанию - это имя, вы можете изменить его самостоятельно)

оптимизация

На самом деле мы обнаружили, что пакет сгенерировалruntime.jsОчень маленький, обычно всего несколько кб после gzip, но этот файл часто меняется, нам нужно каждый раз его перезапрашивать, его http время намного больше, чем время его выполнения, поэтому рекомендуется не распаковывать его отдельно, вместо этого , вставьте его в нашindex.htmlсреди (index.htmlИзначально он будет меняться каждый раз, когда вы упаковываете).

Здесь я выбираюscript-ext-html-webpack-plugin, главным образом потому, что он также поддерживаетpreloadа такжеprefetch, вы не хотите ссылаться на другой плагин, если он вам нужен, вы можете использовать егоinline-manifest-webpack-pluginилиassets-webpack-pluginд., чтобы добиться того же эффекта.

const ScriptExtHtmlWebpackPlugin = require("script-ext-html-webpack-plugin");

// 注意一定要在HtmlWebpackPlugin之后引用
// inline 的name 和你 runtimeChunk 的 name保持一致
new ScriptExtHtmlWebpackPlugin({
  //`runtime` must same as runtimeChunk name. default is `runtime`
  inline: /runtime\..*\.js$/
});

Module vs Chunk

мы часто видимxxxModuleIdsPlugin,xxxChunksPlugin, так что в вебпакеmoduleа такжеchunkЧто это за отношения?

  • Чанк: Относится к файлам (таким как: js, css, изображения и т. д.), на которые есть ссылки в коде, которые будут объединены в один или несколько пакетов в соответствии с конфигурацией. Мы называем пакет фрагментом.
  • модуль: относится к разделению кода на отдельные функциональные блоки в соответствии с их функциями. Разделенный кодовый блок называется модулем. Можно просто понять, что экспорт/импорт — это модуль.

Каждый пакет фрагментов может содержать несколько модулей.Например:

//9.xxxxxxxxx.js

//chunk id为 9 ,包含了Vc2m和JFUb两个module
(window.webpackJsonp = window.webpackJsonp || []).push([
  [9],
  {
    Vc2m: function(e, t, l) {},
    JFUb: function(e, t, l) {}
  }
]);

Одинmoduleможет пересечьchunkпроцитировать другоеmodule, например, я хочуapp.jsнужно процитироватьchunkIdдля13модуль2700Можно процитировать так:

return n.e(13).then(n.bind(null, "27OO"));

HashedModuleIdsPlugin

понялmoduleа такжеchunkПосле этого будем учитьсяmoduleId.

Сначала убедитесь, что ваше имя файла настроено сchunkhash(Разницу между ним и хешем можно увидеть в предыдущей статье).

output: {
  path: path.join(__dirname, 'dist'),
  filename: '[name].[chunkhash].js',
}

Мы только что представили новый файл в записи файлаtest.js

//main.js
import "./test";

//test.js
console.log("apple");

мы бежимnpm run build, обнаружил странную вещь, только что ввел еще один файл, но обнаружил, что изменено не один десяток файлов. Почему это?

Мы случайным образом выбираем файл, сравним его и обнаруживаем, что два файла имеют толькоmodule idс разница.

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

Хотя мы используем [chunkhash] в качестве выходного имени, этого все же недостаточно. Поскольку каждый модуль внутри чанка имеет идентификатор, веб-пакет по умолчанию использует возрастающий номер, какmoduleId. Если вводится новый файл или файл удаляется, это может привести к тому, что другие файлыmoduleIdпроизошли изменения, Тогда кеш недействителен. Такие как:

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

Это причина, решение простое. Давайте не будем использовать автоматически увеличивающийся идентификатор, здесь мы используемHashedModuleIdsPlugin.

или использоватьoptimization.moduleIds v4.16.0Новый выпуск, документация пока нет. Проверитьисходный коднайти это имеетnatural,named,hashed,size,total-size. Здесь мы установленыoptimization.moduleIds='hash'равныйHashedModuleIdsPlugin. Исходный код также написанwebpack5Эта часть кода будет оптимизирована.

Его принцип заключается в использовании пути к файлу в качестве идентификатора и хешировании его в качестве идентификатора модуля.

С помощью HashedModuleIdsPlugin` сравниваем и обнаруживаем, что id модуля уже не простой id, а четырехзначная хеш-строка (не обязательно все четыре цифры, при повторении количество цифр будет увеличено для обеспечения уникальностиисходный код). Это исправляет идентификатор модуля.

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

NamedChunkPlugin

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

Автор также знает об этой проблеме и даетNamedChunkPluginплагин, но в случае ленивой загрузки с маршрутами вы найдетеNamedChunkPluginЭто не помогает. предоставил онлайнdemo, вы можете проверить это сами. Просто вставьте результаты здесь:

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

Тогда мыПосмотреть исходный кодтакже обнаружил, что он работает только сnameКусок просто работает! Таким образом, наши страницы, которые лениво загружаются асинхронно, недействительны. Это не дурак! Наш итеративный бизнес определенно будет постоянно добавлять и удалять страницы.Значит ли это, что каждая новая страница делает предыдущий кеш недействительным? Так какую же распаковку мы потратили столько сил на оптимизацию раньше?

На самом деле это старый вопрос.Vendor chunkhash changes when app code changesКто-то поднял этот вопрос уже в 2015 году, и этот вопрос обсуждался на этот день. «Netizens» также предоставил различные трюки, но большинство из них больше не применимы или не зафиксированы с помощью итерации веб-папа.

Вот совмещу.timse(второй по величине вклад webpack) записан постоянный кешстатья(нужно перевернуть стену на среднем уровне) Обобщите три решения, которые в настоящее время могут решить эту проблему.

На данный момент есть три решения

  • records
  • webpackChunkName
  • пользовательское имяResolver

webpack records

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

Чтобы использовать его, конфигурация также проста:

recordsPath: path.join(__dirname, "records.json");

Да, если эта строка кода может включить эту опцию, и файл JSON будет автоматически создан при упаковке. Он содержит веб-пакетыrecordsЗаписи — фрагменты данных, «используемые для хранения идентификаторов модулей в нескольких сборках». Вы можете использовать этот файл для отслеживания изменений модуля между сборками.

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

Просто взгляните, как выглядит сконструированный JSON.

{
  "modules": {
    "byIdentifier": {
      "demo/vendor.js": 0,
      "demo/vendor-two.js": 1,
      "demo/index.js": 2,
      ....
    },
    "usedIds": {
      "0": 0,
      "1": 1,
      "2": 2,
      ...
    }
  },
  "chunks": {
    "byName": {
      "vendor-two": 0,
      "vendor": 1,
      "entry": 2,
      "runtime": 3
    },
    "byBlocks": {},
    "usedIds": [
      0,
      1,
      2
  }
}

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

Но главная причина, по которой этот план известен не всем, состоит в том, чтобы поддерживать этотrecords.jsonвроде тяжело. Если вы запускаете пакет локальноwebpackЕсли вы просто положитеrecords.jsonЗагрузите как обычный файл вgithub,gitlabили другие репозитории с контролем версий.

Но теперь общая компания положит пакет вCIвнутри, сdockerупаковка, на этот разrecords.jsonГде есть проблема. Ему нужно не только прочитать ваш json перед упаковкой, но и обновить этот json после упаковки, а также найти место для его хранения для использования в следующей сборке. Вы можете хранить его в git или на сервере, но странно существовать где-то еще.

если вы используетеCircle CIможет использовать этоstore_artifacts, Связанныйруководство.

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

webpackChunkName

После версии webpack 2.4.0 имя асинхронного чанка можно настроить, например:

import(/* webpackChunkName: "my-chunk-name" */ "module");

Мы можем написать это в сочетании с ленивой загрузкой Vue.

{
    path: '/test',
    component: () => import(/* webpackChunkName: "test" */ '@/views/test')
  },

После упаковки файл с именемtestфайл чанка.

После того, как у чанка есть имя, его можно решитьNamedChunksPluginОшибка без имени исчезла. Глядя на упакованный код, мы обнаруживаем, что chunkId больше не является простым самоувеличивающимся идентификатором.

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

Так есть ли способ автоматически сгенерировать имя для чанка? Глядя на исходный код веб-пакета, который мы нашлиNamedChunksPluginНа самом деле вы можете настроить nameResolver.

пользовательское имяResolver

NamedChunksPluginПоддерживает написание собственных правил для Nameresolver. Но в настоящее время пользовательские функции в большинстве связанных сопутствующих статей не подходят для WebPack4, и они будут сообщать об ошибках в сочетании с Vue.

Старая схема сообщества:

new webpack.NamedChunksPlugin(chunk => {
  if (chunk.name) {
    return chunk.name;
  }
  return chunk.modules.map(m => path.relative(m.context, m.request)).join("_");
});

Новая реализация для адаптации webpack4 и vue:

new webpack.NamedChunksPlugin(chunk => {
  if (chunk.name) {
    return chunk.name;
  }
  return Array.from(chunk.modulesIterable, m => m.id).join("_");
});

Конечно, это решение все же имеет некоторые недостатки, потому что id может быть очень длинным, а если чанк зависит от многих модулей, то id может состоять из десятков цифр, поэтому нам нужно сократить его длину. Сначала мы помещаем сплайсированный хэш id ниже, и нам нужно убедиться, что количество цифр результата хеширования может быть слишком длинным, что приводит к трате байтов, но оно слишком короткое и подвержено коллизиям, поэтому в конце мы выбираем длину 4 цифры и сделать это вручную с помощью Set Collision check, в случае коллизии количество цифр увеличивается на 1 до тех пор, пока не произойдет коллизия. Подробный код выглядит следующим образом:

const seen = new Set();
const nameLength = 4;

new webpack.NamedChunksPlugin(chunk => {
  if (chunk.name) {
    return chunk.name;
  }
  const modules = Array.from(chunk.modulesIterable);
  if (modules.length > 1) {
    const hash = require("hash-sum");
    const joinedHash = hash(modules.map(m => m.id).join("_"));
    let len = nameLength;
    while (seen.has(joinedHash.substr(0, len))) len++;
    seen.add(joinedHash.substr(0, len));
    return `chunk-${joinedHash.substr(0, len)}`;
  } else {
    return modules[0].id;
  }
});

Я даюvue-cliЧиновник также упомянул связанныйissueYou Yuxi наконец принял этот план. Итак, если вы загрузите последнюю версию сейчасvue-cli@3То, что давно мусолили, на самом деле уже настроено по умолчанию (но сам автор потратил два дня на то, чтобы найти этот метод взлома о(╥﹏╥)о).

Я тестировал его некоторое время и не нашел никаких проблем. Но есть одна вещь, которую я не очень хорошо понимаю, я не знаю, почему webpack не исправил эту проблему. Это может быть увеличение трюка во время ожидания webpack5.

Суммировать

Стратегия распаковки:

  • библиотека базовых классовchunk-libs
  • библиотека компонентов пользовательского интерфейсаchunk-elementUI
  • Пользовательские общие компоненты/функцииchunk-commons
  • низкочастотные компонентыchunk-eachrts/chunk-xlsxЖдать
  • Бизнес-код ленивый загрузкаxxxx.js

Постоянный кеш:

  • использоватьruntimeChunkизвлекатьmanifest,использоватьscript-ext-html-webpack-pluginподождите, пока плагин будет встроен вindex.htmlуменьшить количество запросов
  • использоватьHashedModuleIdsPluginфиксированныйmoduleId
  • использоватьNamedChunkPluginИсправлено с помощью пользовательского nameResolverchunkId

Большинство проблем, упомянутых выше, четко не указаны в официальной документации веб-пакета, единственная ссылка - этокэш-документ, когда только обновлял webpack4, думал, что проблема с официальным id решена, но реальность жестока, и результат неидеален. Впрочем, автор во многих выпусках также говорил, что работает над оптимизациейlong term caching.

We plan to add another way to assign module/chunk ids for long term caching, but this is not ready to be told yet.

Это также часто встречается в задаче и исходном коде веб-пакета.Long term caching will be improved in webpack@5а такжеTODO webpack 5 xxxxТакие комментарии к коду. Это делает меня правымwebpack 5С нетерпением жду. искренне надеюсьwebpack 5Это действительно может решить предыдущие проблемы и сделать их болееout-of-the-box, намного проще и умнее, какwebpack 4изoptimization.splitChunks, вам в принципе ничего не нужно делать, это может помочь вам хорошо разделить егоbundleмешок, и в то же время дает вам большую свободу для игры.

Перспектива

Whats next?В этой статье официальный представитель с нетерпением ждет появления webpack5 и описывает планы на будущее: постоянно улучшать пользовательский опыт, повышать скорость и производительность построения, снижать порог использования, улучшатьPersistent Cachingи т.п. В то же время, веб-пакет также поддерживаетPrefetching/Preloading modules, я считаю, что в будущем этот атрибут будет использоваться на большем количестве веб-сайтов.

В то же время команда WebPack привержена решить некоторые функции через способ голосования. Например, голоса выпущены ранее.

Каждый может следоватьTobias Koppersтвиттер для голосования.

Наконец, с нетерпением ждем webpack5 и его последующего развития. Без webpack сегодня не было бы фронтенда.

На самом деле, как было сказано в начале, vue имеетvue-cli, реакция имеетcreat-react-app, Сейчас новые проекты в основном строятся на скаффолдинге.Мало кто пишет файлы конфигурации вебпака с нуля, да и вообще разработка, рядовым программистам не нужно часто модифицировать конфигурацию вебпака. Сам официальный вебпак тоже постоянно улучшает элементы конфигурации по умолчанию, думаю порог конфигурации вебпака будет все ниже и ниже.

Пусть в мире больше не будет инженеров по настройке веб-пакетов.

Расширенное чтение