предисловие
При разработке многостраничных приложений, если упаковка веб-пакета не оптимизирована, когда на модуль ссылаются несколько входных модулей, он будет упакован несколько раз (в некоторых окончательных упакованных файлах все они будут иметь один и тот же код копирования). Когда проектный бизнес становится все более и более сложным, упакованный код будет очень избыточным, а размер файла будет очень большим. Большие файлы увеличат время компиляции и повлияют на эффективность разработки; если вы выходите в интернет напрямую, это также удлинит запрос и время загрузки, что повлияет на работу веб-сайта. Для осадного льва, стремящегося к высшему опыту, это невыносимо. Поэтому особенно необходимо оптимизировать упаковку в многостраничных приложениях. Итак, как оптимизировать упаковку веб-пакета?
1. Концепция
Прежде чем мы начнем, необходимо прояснить эти три понятия:
- модуль: модуль, в глазах веб-пакета любой файл, который можно импортировать и экспортировать, является модулем.
- чанк: чанк разделен веб-пакетом:
- Каждый входной файл представляет собой фрагмент
- Код, введенный через import и require, также
- Код, разделенный splitChunks, также
- пакет: файлы, упакованные webpack, также можно понимать как результат компиляции, сжатия и упаковки фрагментов.
2. Анализ проблемы
Во-первых, при простом анализе проблема упаковки, которую мы только что упомянули:
- Основная проблема заключается в следующем: после упаковки многостраничного приложения код становится избыточным, а размер файла большим.
- Причина в том, что одни и те же модули не используются повторно между разными записями, а пакеты относительно независимы.
После понимания причины проблемы выйдет общее решение:
- Когда мы упаковываем, мы должны извлечь модули, на которые обычно ссылаются разные записи, и поместить их в общий модуль. Таким образом, независимо от того, сколько записей ссылается на этот модуль, он появится только один раз в конечном результате упаковки. —— Устранение избыточности кода.
- Кроме того, когда мы складываем эти часто используемые модули в один модуль, файл может быть очень большим, что также не способствует сетевым запросам и загрузке страниц. Поэтому нам нужно дополнительно разбить этот общий модуль на несколько файлов модулей по определенным правилам. —— Уменьшите размер файла.
- Что касается того, как разделить, способ варьируется от человека к проекту и от проекта к проекту. Мой личный принцип разделения:
- Бизнес-код и сторонние библиотеки разделены и упакованы для обеспечения сегментации кода;
- Код обслуживания, общий для упаковочного модуля, извлекивает сервисный модуль;
- Лучше не упаковывать все сторонние библиотеки в один файл,потому что сторонние библиотеки обычно очень большие.Некоторые особо большие библиотеки я упакую отдельно.Если остальные все же очень большие,соберите их вместе.Разрежьте на несколько модули в соответствии с определенным размером.
optimization.splitChunks
webpack предоставляет очень хороший встроенный плагин, который поможет нам выполнить это требование:CommonsChunkPlugin
. Но в вебпаке4CommonsChunkPlugin
удаляется и заменяетсяoptimization.splitChunks
, к счастьюoptimization.splitChunks
Более могущественный!
3. Реализация
С помощью небольшой демонстрации многостраничного приложения мы шаг за шагом реализуем конфигурацию изложенных выше идей.
демо структура каталогов:
|--public/
| |--a.html
| |--index.html
|--src/
| |--a.js
| |--b.js
| |--c.js
| |--index.js
|--package.json
|--webpack.config.js
Логика кода очень проста,index
ссылка в модулеa
а такжеb
2 модуля,a
ссылка в модулеc
модули иjquery
библиотека,b
Также упоминается в модулеc
модули иjquery
библиотека,c
является автономным модулем без каких-либо других зависимостей.
Код index.js выглядит следующим образом:
//index.js
import a from './a.js';
import b from './b.js';
function fn() {
console.log('index-------');
}
fn();
Код A.js выглядит следующим образом:
//a.js
require('./c.js');
const $ = require('jquery')
function fn() {
console.log('a-------');
}
module.exports = fn();
код b.js выглядит следующим образом:
//b.js
require('./c.js');
const $ = require('jquery')
function fn() {
console.log('b-------');
}
module.exports = fn();
код c.js выглядит следующим образом:
//c.js
function fn() {
console.log('c-------');
}
module.exports = fn();
1. Базовая конфигурация
Webpack сначала не оптимизируется, просто выполните базовую настройку и посмотрите на эффект. Проект сконфигурирован с 2 входами, сhtml-webpack-plugin
Реализовать многостраничную упаковку:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
index: './src/index.js',
a: './src/a.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html'
}),
new HtmlWebpackPlugin({
template: './public/a.html',
filename: 'a.html'
})
]
}
Запустите webpack в режиме разработки:
Как видите, запакованы два html и два больших (более 300 Кб) файла.a.js
,index.js
.
Войдите в каталог dist, чтобы проверить файл js:
-
a.js
содержитc
код модуля иjquery
код -
index.js
содержитa
модуль,b
модуль,c
модули иjquery
код
смотри, тот же кодc
а такжеjquery
Упаковано 2 раза.
2. Первоначально добавьте конфигурацию оптимизации splitChunks
Во-первых, чтобы решить проблему упаковки одного и того же кода дважды, нам нужно разрешить webpack помещатьc
а такжеjquery
Извлечен и упакован как общедоступный модуль.
Добавьте splitChunks в файл конфигурации webpack:
//webpack.config.js
optimization: {
splitChunks: {
cacheGroups: {
default: {
name: 'common',
chunks: 'initial'
}
}
}
}
- cacheGroups
-
cacheGroups
даsplitChunks
Ядро конфигурации, правила разделения кода — все вcacheGroups
Настраивается в группе cache. - Каждое свойство группы cache является конфигурационным правилом, я приведу его здесь.
default
Атрибут настроен, и имя атрибута можно задать самостоятельно вместо значения по умолчанию. - Значением свойства является объект, который содержит наше описание правила разделения кода.
- name
- имя: Извлеченный общедоступный модуль будет назван в соответствии с этим. Его можно оставить ненастроенным. Если он не настроен, будет сгенерировано имя файла по умолчанию. Приблизительный формат:
index~a.js
Такой.
- chunks
- чанки: Указывает, какие типы чанков участвуют в разбиении.Значение может быть строкой или функцией. Если строка, может быть одним из этих трех значений:
all
,async
,initial
,all
представляет все модули,async
Представляет только асинхронную загрузку,initial
Представляет модуль, который можно получить во время инициализации. Если это функция, вы можете выполнить более подробную фильтрацию на основе таких атрибутов, как имя параметра фрагмента.
Упакуйте снова:
можно увидетьa.js
,index.js
Уменьшено с более чем 300 К до нескольких К в 6.00. Также добавленcommon.js
файл, и обе записи упаковки добавляются автоматическиcommon.js
Этот общедоступный модуль:
Войдите в каталог dist и просмотрите три файла js по очереди:
-
a.js
Он не содержит никакого кода модуля, только код по умолчанию, сгенерированный webpack. -
index.js
Он также не содержит никакого кода модуля, только код по умолчанию, сгенерированный webpack. -
common.js
внутриa
,b
,c
,index
,jquery
код.
Выяснилось, что упоминание было извлечено, но, похоже, оно отличается от того, что мы ожидали.common.js
пошел в.
Это потому, что мы не сказали webpack (splitChunks
) какой код является общедоступным кодом,splitChunks
По умолчанию любой модуль будет извлечен.
- minChunks
splitChunks
Он поставляется со своей собственной конфигурацией по умолчанию, и группа кеша наследует эти конфигурации по умолчанию, одна из которыхminChunks
Атрибуты:
- Он контролирует, когда извлекается каждый модуль: когда количество ссылок на модуль в разных записях больше или равно этому значению конфигурации, он будет извлечен.
- Его значение по умолчанию равно 1. То есть любой модуль будет извлечен (модуль входа фактически будет один раз импортирован вебпаком).
У нас нет конфигурации вышеminChunks
, только настроеноname
а такжеchunk
два свойства, поэтомуminChunks
значение по умолчанию1
эффективный. Неудивительно, что все модули извлекаются вcommon.js
бинго.
Оптимизируйте его и настройте в группе кешаminChunks
Переопределить значение по умолчанию:
//webpack.config.js
optimization: {
splitChunks: {
cacheGroups: {
default: {
name: 'common',
chunks: 'initial',
minChunks: 2 //模块被引用2次以上的才抽离
}
}
}
}
затем запустите веб-пакет
Вы можете видеть, что размер 2 файлов изменился:common.js
Уменьшено с 314К до 311К,index.js
Увеличено с 6,22К до 7,56К.
Войдите в каталог dist для просмотра:
-
a.js
по-прежнему не содержит никакого кода модуля (нормально, т.к.a
как модульindex
Представлен один раз и представлен один раз веб-пакетом в качестве записи, поэтомуa
цитируется 2 раза). -
index.js
появился вb
а такжеindex
код модуля. -
common.js
осталось толькоa
,c
,а такжеjquery
код модуля.
Теперь мы помещаем модуль со ссылкойa
, c
, jquery
,отa
а такжеindex
Извлечено из этих двух входных модулейcommon.js
в. Немного соответствует нашим ожиданиям.
3. Настройте несколько правил разделения
3.1 Реализовать разделение кода и разделить сторонние библиотеки
Далее я хочу общедоступный модульcommon.js
, бизнес-код и сторонний модуль jquery можно разделить.
Нам нужно добавить еще одно правило разделения.
//webpack.config.js
optimization: {
splitChunks: {
minSize: 30, //提取出的chunk的最小大小
cacheGroups: {
default: {
name: 'common',
chunks: 'initial',
minChunks: 2, //模块被引用2次以上的才抽离
priority: -20
},
vendors: { //拆分第三方库(通过npm|yarn安装的库)
test: /[\\/]node_modules[\\/]/,
name: 'vendor',
chunks: 'initial',
priority: -10
}
}
}
}
Я добавил атрибут поставщика в cacheGroups (имя атрибута можно взять самостоятельно, если оно не совпадает с именем других определенных атрибутов в группе кеша, иначе последующие правила разделения перезапишут предыдущую конфигурацию).
- minSize
minSize устанавливает минимальный размер сгенерированного файла в байтах. Если модуль соответствует упомянутым ранее правилам разбиения, но окончательный размер сгенерированного файла меньше minSize, он все равно не будет извлечен. Это свойство можно задать в каждом свойстве группы кэша или в свойстве splitChunks, чтобы эта конфигурация наследовалась в каждой группе кэша. Здесь, поскольку файлы в моем демо очень маленькие, чтобы продемонстрировать эффект, я установил minSize в 30 байт, чтобы можно было извлечь общие модули.В обычных проектах не обязательно устанавливать такой маленький размер.
- priority
Значением атрибута приоритета является число, которое может быть отрицательным. В результате, когда в группе кэша установлено несколько правил разделения, и модуль соответствует нескольким правилам одновременно, атрибут приоритета необходим, чтобы решить, какое правило разделения использовать. Выполняется тот, у кого выше приоритет. Я установил приоритет для группы бизнес-кода на -20, а приоритет для группы сторонних библиотек на -10, чтобы при ссылке на стороннюю библиотеку более 2 раз она не была упакована в бизнес модуль. .
- test
Атрибут test используется для дальнейшего управления модулями, выбранными группой кеша, который аналогичен атрибуту chunks, но отличается размерами. Значение test может быть регулярным выражением или функцией. Он может совпадать с абсолютным путем к ресурсу модуля или имени чанка. При совпадении с именем чанка будут выбраны все модули в чанке. Я использовал обычный здесь/[\\/]node_modules[\\/]/
Чтобы соответствовать абсолютному пути сторонних модулей, потому что модули, установленные через npm или yarn, будут храниться в каталоге node_modules.
Запустите веб-пакет:
Вы можете видеть, что новый вызовvendor.js
файл (значение атрибута name), аcommon.js
Размер файла был уменьшен с исходных 311k до 861 байт!
Перейдите в каталог dist и проверьте файл js:
-
a.js
Он не содержит никакого кода модуля. -
common.js
содержит толькоa
а такжеc
код модуля. -
index.js
содержит толькоb
а такжеindex
код модуля. -
vendor.js
содержит толькоjquery
код модуля.
Теперь, на основе предыдущего шага, мы успешноcommon.js
сторонняя библиотекаjquery
Вынь и вставьvendor.js
внутри.
3.2 Разделить указанный файл
Если мы также хотим отдельно упаковать некоторые файлы в проекте (например, библиотеку компонентов, разработанную локально в проекте), мы можем продолжить добавлять правила разделения. Например, под моим src естьlocallib.js
Файлы должны быть упакованы отдельно, предполагаяa.js
Он был введен в .
//a.js
require('./c.js');
require('./locallib.js'); //引入自己本地的库
const $ = require('jquery')
function fn() {
console.log('a-------');
}
module.exports = fn();
Его можно настроить так:
//webpack.config.js
optimization: {
splitChunks: {
minSize: 30, //提取出的chunk的最小大小
cacheGroups: {
default: {
name: 'common',
chunks: 'initial',
minChunks: 2, //模块被引用2次以上的才抽离
priority: -20
},
vendors: { //拆分第三方库(通过npm|yarn安装的库)
test: /[\\/]node_modules[\\/]/,
name: 'vendor',
chunks: 'initial',
priority: -10
},
locallib: { //拆分指定文件
test: /(src\/locallib\.js)$/,
name: 'locallib',
chunks: 'initial',
priority: -9
}
}
}
}
Я добавил новое правило разбиения под группу кеша, и я должен упаковать его отдельно, указав периодичность проверки.src/locallib.js
файл и установите приоритет равным -9, чтобы при многократном обращении к нему он не попадал в другие группы разделенных правил, поскольку два других правила имеют более низкий приоритет, чем этот.
После запуска упаковки webpack:
Видно, что новое поколениеlocallib.js
документ. Войдите в каталог dist для просмотра:
-
a.js
Он не содержит никакого кода модуля. -
common.js
содержит толькоa
а такжеc
код модуля. -
index.js
содержит толькоb
а такжеindex
код модуля. -
vendor.js
содержит толькоjquery
код модуля. -
locallib.js
содержит толькоlocallib
код модуля.
Теперь мы упаковываем указанный модуль самостоятельно на основе предыдущего шага.locallib.js
.
На данный момент мы успешно реализовали извлечение общедоступных модулей, удаление бизнес-кода и стороннего кода, а также независимую упаковку указанных модулей.
Для сравнения, до оптимизации упакованный js имеет общий размер 633 КБ:
После оптимизации упакованный js в сумме составляет менее 330 КБ:
Оптимизированные и упакованные файлы четко классифицированы, а их объем почти на 50% меньше, чем до оптимизации. Дай пять! Это всего лишь простой пример, который я привел: в реальных многостраничных приложениях может потребоваться больше усилий по оптимизации.
резюме
Webpack очень мощный, вышеизложенное — лишь верхушка айсберга, но до тех пор, пока вы овладеваете вышеперечисленнымoptimization.splitChunks
Базовая конфигурация, мы можем разделить оптимизированные файлы пакета управления кодом почти произвольно в соответствии с нашими собственными идеями, разве это не круто? Поэкспериментируйте с разделением кода, и вы тоже сможете!
Если вы чувствуете, что они все еще не могут удовлетворить ваши потребности, и вы хотите более точно настроить правила упаковки, вы можете перейти кофициальный сайт вебпакаПроверить
optimization.splitChunks
больше конфигурации.
Добро пожаловать на общение~
Полную конфигурацию веб-пакета и исходный код демо для этой статьи можно найти здесь:GitHub.com/so 111/Веб боится…
--
Добро пожаловать в перепечатку, пожалуйста, укажите источник:
Найдите Pinyin.com/2019/11/15/…