В предыдущих статьях мы узнали об основном использовании и принципах веб-пакета:
- webpack от мелкой до глубокой серии (1)
- Webpack от мелкой до глубокой серии (2)
- Анализ выходных файлов webpack
- Упакуйте библиотеку компонентов vue по требованию с помощью webpack
- Тщательно понять принцип веб-пакета: написать основной код веб-пакета от руки.
Когда проект становится все более сложным, он столкнется с проблемой, что объем файла будет медленным и построенным. Оптимизация сборки Webapck — это вещь, которую необходимо учитывать для крупных проектов.Здесь мы обсуждаем построение политик оптимизации по скорости и объему.
инструмент для анализа
Перед оптимизацией нам нужно понять некоторые инструменты количественного анализа и использовать их, чтобы помочь нам проанализировать точки, которые необходимо оптимизировать.
webpackbar
webpackbar может отображать процесс упаковки в режиме реального времени во время упаковки. Конфигурация также очень проста, просто добавьте ее в массив плагинов:
const WebpackBar = require('webpackbar')
module.exports = {
plugins: [
...
new WebpackBar()
]
}
speed-measure-webpack-plugin
использоватьspeed-measure-webpack-plugin
Вы можете увидеть трудоемкую ситуацию каждого загрузчика и плагина.
Он немного отличается от использования обычных плагинов, он должен обернуть весь элемент конфигурации webpack своим методом wrap.
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin')
const smp = new SpeedMeasurePlugin()
module.exports = smp.wrap({
entry: './src/main.js',
...
})
После упаковки вывод информации в командную строку следующий, мы можем посмотреть какие загрузчики и плагины долго работают, а потом оптимизировать их.
webpack-bundle-analyzer
webpack-bundle-analyzer
Наглядным способом мы можем наглядно увидеть, какой контент модуля входит в упакованный пакет, и размер каждого модуля. На основе этой информации мы можем анализировать структуру проекта, корректировать конфигурацию упаковки и оптимизировать.
Добавьте плагин на массив плагинов. После завершения сборки по умолчанию будет вhttp://127.0.0.1:8888/
Отобразите результаты анализа.
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports = {
plugins: [
...
new BundleAnalyzerPlugin()
]
}
webpack-bundle-analyzer
Размер файла модуля рассчитывается в трех случаях:
- stat: исходный размер файла без преобразования
- parsed: выходной размер файла после преобразования (например, преобразование babel-loader ES6-> ES5, сжатие UglifyJsPlugin и т. д.)
- gzip: размер анализируемого файла после сжатия Gzip.
использоватьspeed-measure-webpack-plugin
а такжеwebpack-bundle-analyzer
само по себе также увеличит время упаковки (webpack-bundle-analyzer
Это занимает особенно много времени), поэтому рекомендуется использовать эти два плагина в анализе разработки и удалить их в производственной среде.
Оптимизировать скорость сборки
многопроцессная сборка
Webpack, работающий на Node.js, является однопоточным. Даже если несколько задач существуют одновременно, они могут быть поставлены в очередь на выполнение только одна за другой. Когда проект более сложный, сборка будет медленнее. Сегодня большинство ЦП являются многоядерными, и мы можем использовать некоторые инструменты, чтобы полностью реализовать преимущества ЦП в многоядерном параллелизме.
Более распространеныhappypack
,thread-loader
.
happypack
happypack может разбить задачу сборки на несколько подпроцессов для одновременного выполнения, а затем отправить результат в основной процесс после того, как подпроцессы его обработают. Конфигурация выглядит следующим образом: исходная конфигурация загрузчика передается в happyPack для обработки.
const Happypack = require('happypack')
module.exports = {
module:{
rules:[
{
test: /\.js$/,
use: 'happypack/loader?id=babel' //问号后面的查询参数指定了处理这类文件的HappyPack实例的名字
},
]
},
plugins:[
new Happypack({
id: 'babel', //HappyPack实例名,对应上面rules中的“id=babel”
use: ['babel-loader'] //原本要使用的loader
})
]
}
thread-loader
Автор happypack больше не поддерживает этот проект.После webpack4 вы можете использоватьthread-loader
.
thread-loader
Его очень просто использовать, просто поместите его перед другими загрузчиками, как показано ниже. размещены в этомthread-loader
Последующие загрузчики будут работать в отдельном пуле рабочих процессов.
module.exports = {
module:{
rules:[
{
test: /\.js$/,
use: ['thread-loader','babel-loader']
}
]
},
}
Если это небольшой проект, не рекомендуется запускать многопроцессную сборку, поскольку для запуска процесса требуется время, и скорость сборки будет ниже.
Использовать кеш
Использование кеша может повысить скорость вторичного построения (следующие сравнительные диаграммы посвящены скорости вторичного построения). После использования кеша в node_modules будет.cache
Каталог для хранения кэшированного контента.
cache-loader
Добавьте это перед некоторыми загрузчиками с высокой производительностью.cache-loader
, чтобы кэшировать результаты на диск.
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: ['cache-loader','babel-loader']
}
]
}
}
Видно, что с помощьюcache-loader
После этого скорость сборки была значительно улучшена.
правильноbabel-loader
Использовать кеш или нетcache-loader
прямо вbabel-loader
добавить после?cacheDirectory=true
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: ['babel-loader?cacheDirectory=true']
}
]
}
}
hard-source-webpack-plugin
hard-source-webpack-plugin
Используется для включения кэширования модуля.
const HardSourceWebpackPlugin = require("hard-source-webpack-plugin")
module.exports = {
plugins:[
new HardSourceWebpackPlugin()
]
}
использоватьhard-source-webpack-plugin
После второго здания, чтобы повысить скорость около 90%.
include/exclude
Обычно загрузчик обрабатывает все файлы, соответствующие правилам сопоставления. Например, babel-loader будет просматривать все js-файлы, используемые в проекте, компилировать и преобразовывать код каждого файла. Файлы js в node_modules в основном переведены и не нуждаются в повторной обработке, поэтому мы используем include/exclude, чтобы избежать этого ненужного перевода.
module.exports = {
module:{
rules:[
{
test: /\.js$/,
use: ['babel-loader'],
exclude: /node_modules/
//或者 include: [path.resolve(__dirname, 'src')]
}
]
},
}
Включить напрямую указывает папку поиска, что более эффективно, чем исключение, и может повысить скорость сборки.
динамически подключаемая библиотека
Вышеупомянутый загрузчик babel может избежать обработки сторонних библиотек в node_modules через include/exclude.
Однако, если код сторонней библиотеки и бизнес-код упакованы в пакетный файл, то подключаемые модули, обрабатывающие этот пакетный файл, такие как uglifyjs-webpack-plugin, terser-webpack-plugin и т. д., не имеют возможности не обрабатывать содержимое сторонней библиотеки внутри.
На самом деле, сторонний библиотечный код в основном созревает, какой процесс нет. Следовательно, мы можем проецировать сторонний библиотечный код разделен.
Общее лечение тремя способами:
- Externals
- SplitChunks
- DllPlugin
Внешние файлы могут не иметь дело со сторонними библиотеками, но каждая сторонняя библиотека должна быть введена путем добавления тега скрипта в html-документ. использовать сторонние библиотеки Неразумно вводить небольшое количество функций полностью тегами скрипта.
SplitChunks перестраивает стороннюю библиотеку каждый раз при ее сборке, что не может эффективно повысить скорость сборки.
Рекомендуется использовать DllPlugin и DLLReferencePlugin (используются вместе), которые являются встроенными плагинами webpack. DllPlugin отдельно упакует редко обновляемые сторонние библиотеки, когда версии этих сторонних библиотек не менялись, пересборка не требуется.
Инструкции:
- Используйте DllPlugin для упаковки сторонних библиотек
- Используйте DLLReferencePlugin для ссылки на manifest.json, чтобы связать пакет, который был введен на шаге 1.
- Сначала создайте файл конфигурации webpack
webpack.dll.js
Для упаковки сторонних библиотек (шаг 1)
const path = require('path')
const webpack = require('webpack')
module.exports = {
mode: 'production',
entry: {
three: ['three', 'dat.gui'] // 第三方库数组
},
output: {
filename: '[name].dll.js', //[name]就是在entry
path: path.resolve(__dirname, 'dist/lib'),
library: '[name]'
},
plugins: [
new webpack.DllPlugin({
name: '[name]',
path: path.resolve(__dirname, 'dist/lib/[name].json') //manifest.json的存放位置
})
]
}
После упаковки вы можете увидеть, что вdist
Папка lib добавляется в каталог.
- Тогда мы
webpack.base.js
Внесите некоторые изменения, чтобы связать пакет, который был введен на шаге 1 (шаг 2).
module.exports = {
plugins:[
//修改CleanWebpackPlugin配置
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: [
'!lib/**' //在每次清楚dist目录时,不清理lib文件夹的内容
]
}),
// dll相关配置
new webpack.DllReferencePlugin({
// 将manifest字段配置成我们第1步中打包出来的json文件
manifest: require('./dist/lib/three.json')
})
]
}
После пакет снова видно, по сравнению с началом объем всего проекта 9.11мб, объем уменьшен на 90%, т.к. это многостраничный пакет(Конфигурация многостраничного пакета), каждая страница ссылается на громоздкийthree.js核心文件
, берем наибольший объемthree.js核心文件
После извлечения из пакета каждой страницы размер пакета значительно уменьшается.
Посмотрим на время сборки: по сравнению с тем, что было до использования DllPlugin, время сократилось на 30%.
DllPlugin может отделять не только сторонние библиотеки, но и базовые библиотеки в бизнес-коде.
Оптимизированный объем сборки
разделение кода
Разделите базовую библиотеку на стороннюю библиотеку и бизнес-код, избегая единого размера bundle.js, время загрузки слишком велико. И в многостраничной конструкции это также может уменьшить упаковку.
Обычная операция осуществляется черезSplitChunks(В предыдущей статье подробно написано:SplitChunks)а такжединамически подключаемая библиотека(Как показано выше) и не будет повторяться здесь.
Динамический импорт
Роль динамического импорта в основном заключается в уменьшении объема ресурсов выше сгиба, а ресурсы, которые не находятся выше сгиба, будут запрашиваться при их использовании, тем самым повышая скорость загрузки выше сгиба. Типичным примером является управление маршрутизацией для одностраничных приложений (таких какvue-router
)
{
path: '/list',
name: 'List',
component: () => import('../views/List.vue')
},
не импортировать компоненты напрямую (import List from '../views/List.vue'
), который упакует компоненты в один и тот же пакет. Вместо этого импортируйте компоненты динамически,любой пропускimport()
Ссылочные модули упакованы в отдельные пакетыКогда вы используете его, вы загрузите его. Для функциональных комплексов не рекомендуется использовать динамический ИМПОРТ.
<span @click="loadModal">show弹窗</span>
/***
methods: {
loadModal(){
import('../modal/index.js')
}
}
***/
treeShaking
Используйте синтаксис импорта/экспорта ES6 и импортируйте и экспортируйте свой код, используя следующие методы вместо экспорта по умолчанию.
// util.js 导出
export const a = 1
export const b = 2
export function afunc(){}
或
export { a, b, afunc }
// index.js 导入
import { a, b } from './util.js'
console.log(a,b)
затем вmode:production
производственной среде, он автоматически откроетсяtree-shaking
, удалите неиспользуемый код, в приведенном выше примереafunc函数
не будет упакован в комплект.
сжатие кода
Обычно используемые плагины сжатия кода js:uglifyjs-webpack-plugin
а такжеterser-webpack-plugin
.
В WebPack4 сжатие кода включается по умолчанию в производственных условиях. Мы также можем настроить на себя, чтобы переопределить конфигурацию по умолчанию для завершения более индивидуальных требований.
До версии 4.26.0 встроенный плагин сжатия веб-пакета был uglifyjs-webpack-plugin, начиная с версии 4.26.0 он был заменен на uglifyjs-webpack-plugin.terser-webpack-plugin
. Здесь мы такжеterser-webpack-plugin
Например, в отличие от использования обычных плагинов, вoptimization.minimizer
Настройте плагин сжатия в
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
optimization: {
minimizer: [
new TerserPlugin({
parallel: true, //开启并行压缩,可以加快构建速度
sourceMap: true, //如果生产环境使用source-maps,则必须设置为true
})
]
}
}
Спрайт
Карта спрайтов объединяет несколько маленьких значков в большое изображение.В среде HTTP1.x карта спрайтов может уменьшить HTTP-запросы и увеличить скорость отображения веб-страниц.
Иконка, используемая для синтеза изображения спрайта, должна быть небольшого размера, и не рекомендуется вставлять большее изображение в изображение спрайта, в то же время, если это статическая иконка сайта, она не является иконкой динамически. получен через ajax-запрос. Поэтому он обычно используется в качестве логотипа веб-сайта, значка и других изображений.
Во время разработки пользовательский интерфейс может предоставить изображение спрайта, но каждый раз, когда добавляется иконка, ее нужно создавать заново и пересчитывать смещение, что хлопотно. Синтезируя изображение спрайта через плагин webpack, вы можете напрямую использовать одну маленькую иконку во время разработки.При упаковке изображение спрайта автоматически синтезируется, а css в css автоматически модифицируется.background-position
ценность .
Ниже мы используемpostcss-sprites
автоматически синтезировать изображения спрайтов.
Первый вwebpack.base.js
Средняя конфигурацияpostcss-loader
:
//webpack.base.js
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: ['vue-style-loader','css-loader', 'postcss-loader'] //配置postcss-loader
},
{
test: /\.less$/,
use: [
'vue-style-loader','css-loader', 'postcss-loader', 'less-loader'] //配置postcss-loader
}
]
}
};
Затем создайте новый в корневом каталоге проекта..postcssrc.js
, настроитьpostcss-sprites
.
module.exports = {
"plugins": [
require('postcss-sprites')({
// 默认会合并css中用到的所有静态图片
// 使用filterBy指定需要合并的图片,比如这里这里只合并images/icon文件夹下的图片
filterBy: function (image) {
if (image.url.indexOf('/images/icon/') > -1) {
return Promise.resolve();
}
return Promise.reject();
}
})
]
}
По умолчанию изображения будут объединены вsprite.png
иллюстрация спрайта.
Непосредственно укажите маленькую иконку в качестве фона в css:
.star{
display: inline-block;
height: 100px;
width: 100px;
&.l1{
background: url('../icon/star.png') no-repeat;
}
&.l2{
background: url('../icon/star2.png') no-repeat;
}
&.l3{
background: url('../icon/star3.png') no-repeat;
}
}
После завершения упаковки вы можете увидеть, что она автоматически модифицируется.background-image
а такжеbackground-position
.
gzip
Принцип gzip, ссылкаИзучение секретов сжатия gzip в HTTP-транспорте
Включите сжатие gzip, чтобы уменьшить размер файла. Когда браузер поддерживает gzip, он может ускорить загрузку ресурсов. И сервер, и клиент могут выполнять сжатие gzip, сервер сжимает при ответе на запрос, а клиент сжимает при сборке приложения. Однако процесс сжатия файлов требует времени и ресурсов процессора, а большое количество требований к сжатию увеличивает нагрузку на сервер.
Таким образом, вы можете генерировать сжатые файлы gzip при сборке и упаковке, размещать их на сервере как статические ресурсы и возвращать сжатые файлы сразу после получения запроса.
Использование webpack для создания файлов gzip требует помощиcompression-webpack-plugin
, используя конфигурацию следующим образом:
const CompressionWebpackPlugin = require("compression-webpack-plugin")
module.exports = {
plugins: [
new CompressionWebpackPlugin({
test: /\.(js|css)$/, //匹配要压缩的文件
algorithm: "gzip"
})
]
}
адрес проекта: GitHub.com/Alxa О Лала/Я…