Подробно разблокируйте серию Webpack (базовая)а такжеПодробно разблокируйте серию Webpack (дополнительно), в основном для объясненияWebpack
Конфигурация, но поскольку проект становится больше и больше, скорость сборки может стать медленнее и медленнее, а объем построенного js также станет больше и больше. В это время надоWebpack
конфигурация оптимизирована.
В этой статье перечислены более десяти методов оптимизации. Вы можете выбрать подходящий метод для оптимизации в соответствии с вашим собственным проектом. ЭтиWebpack
Я не видел большую часть исходного кода плагина, в основном из-за комбинацииWebpack
Официальные документы и практики проекта, а также потратил много времени на проверку и вывод этой статьи.Если в тексте есть ошибки, пожалуйста, исправьте их в поле для комментариев.
Ввиду быстрых изменений в передовых технологиях, эта статья основана наWebpack
номер версии:
├── webpack@4.41.5
└── webpack-cli@3.3.10
Адрес проекта, соответствующий этой статье (использованный при написании этой статьи), предназначен для справки:GitHub.com/Иветт Л.А. У/И…
количественно
Иногда оптимизация, которую мы думаем, является отрицательной оптимизацией.В настоящее время, если есть количественный показатель, чтобы увидеть сравнение до и после, это будет лучше всего.
speed-measure-webpack-plugin
Плагины могут измерять отдельные плагины иloader
Затраченное время, после использования, при постройке у вас получится примерно так:
speed-measure-webpack-pluginИспользование очень простое, вы можете напрямую использовать его для обертыванияWebpack
Конфигурация:
//webpack.config.js
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
const config = {
//...webpack配置
}
module.exports = smp.wrap(config);
1.exclude/include
мы можем пройтиexclude
,include
Настройте так, чтобы транспилировалось как можно меньше файлов. Как подсказывает название,exclude
указать файлы для исключения,include
Указывает файлы для включения.
exclude
приоритет выше, чемinclude
,существуетinclude
а такжеexclude
Используйте массивы абсолютных путей в , старайтесь избегатьexclude
, предпочитаю использоватьinclude
.
//webpack.config.js
const path = require('path');
module.exports = {
//...
module: {
rules: [
{
test: /\.js[x]?$/,
use: ['babel-loader'],
include: [path.resolve(__dirname, 'src')]
}
]
},
}
На картинке ниже то, что я не настроилinclude
и настроенinclude
Сравнение результатов сборки:
2. cache-loader
В некоторых накладных расходахloader
добавлено доcache-loader
, кэшировать результаты на диске. По умолчанию сохраняется вnode_modueles/.cache/cache-loader
Под содержанием.
Сначала установите зависимости:
npm install cache-loader -D
cache-loader
Конфигурация очень простая, поставь в др.loader
до. ИсправлятьWebpack
Конфигурация выглядит следующим образом:
module.exports = {
//...
module: {
//我的项目中,babel-loader耗时比较长,所以我给它配置了`cache-loader`
rules: [
{
test: /\.jsx?$/,
use: ['cache-loader','babel-loader']
}
]
}
}
Если вы похожи на меня, только собираетесь датьbabel-loader
настроитьcache
, вы также можете не использоватьcache-loader
,Датьbabel-loader
добавить параметрыcacheDirectory
.
cacheDirectory
: значение по умолчаниюfalse
. Если установлено, указанный каталог будет использоваться для кэшированияloader
результат исполнения. ПослеWebpack
Сборка попытается прочитать кеш, чтобы избежать высокого потребления производительности, которое может происходить каждый раз при ее выполнении.Babel
Процесс перекомпиляции. установить нулевое значение илиtrue
Если это так, используйте каталог кеша по умолчанию:node_modules/.cache/babel-loader
. включиbabel-loader
кеш и конфигурацияcache-loader
Я сравнил это, время сборки очень близко.
3.happypack
Из-за большого количества файлов, которые необходимо проанализировать и обработать, сборка представляет собой операцию чтения файлов и интенсивных вычислений, особенно когда количество файлов увеличивается.Webpack
Проблема медленных сборок может быть серьезной. Чтение и запись файлов, а также вычислительные операции неизбежны.Webpack
Как насчет одновременной обработки нескольких задач и использования мощности компьютеров с многоядерными процессорами для ускорения сборки?
HappyPack
может сделатьWebpack
Для этого он разбивает задачу на несколько подпроцессов для одновременного выполнения, а подпроцессы обрабатывают результат, а затем отправляют результат в основной процесс.
Сначала нужно установитьhappypack
:
npm install happypack -D
Измените файл конфигурации:
const Happypack = require('happypack');
module.exports = {
//...
module: {
rules: [
{
test: /\.js[x]?$/,
use: 'Happypack/loader?id=js',
include: [path.resolve(__dirname, 'src')]
},
{
test: /\.css$/,
use: 'Happypack/loader?id=css',
include: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'node_modules', 'bootstrap', 'dist')
]
}
]
},
plugins: [
new Happypack({
id: 'js', //和rule中的id=js对应
//将之前 rule 中的 loader 在此配置
use: ['babel-loader'] //必须是数组
}),
new Happypack({
id: 'css',//和rule中的id=css对应
use: ['style-loader', 'css-loader','postcss-loader'],
})
]
}
happypack
Включено по умолчаниюCPU核数 - 1
процесс, конечно, мы также можем пройтиthreads
ДатьHappypack
.
Описание: когдаpostcss-loader
настроен вHappypack
В проекте необходимо создать его в проекте.postcss.config.js
.
//postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')()
]
}
В противном случае будет выброшена ошибка:Error: No PostCSS Config found
Кроме того, когда ваш проект не очень сложный, настройка не требуется.happypack
, т.к. выделение и управление процессом также требует времени, что не улучшает скорость строительства эффективно, а даже замедляет.
4.thread-loader
Помимо использованияHappypack
В качестве альтернативы мы также можем использоватьthread-loader
,Пучокthread-loader
размещены в другихloader
раньше, затем поместите этоloader
Послеloader
будет в отдельномworker
бег в бассейне.
Загрузчики, работающие в рабочем пуле, ограничены. Например:
- Эти
loader
Новый файл не может быть сгенерирован. - Эти
loader
не могу использовать пользовательскийloader
API (то есть через плагины). - Эти
loader
недоступноwebpack
настройки опции.
Сначала установите зависимости:
npm install thread-loader -D
Изменить настройку:
module.exports = {
module: {
//我的项目中,babel-loader耗时比较长,所以我给它配置 thread-loader
rules: [
{
test: /\.jsx?$/,
use: ['thread-loader', 'cache-loader', 'babel-loader']
}
]
}
}
thread-loader
а такжеHappypack
Я сравнил, время сборки практически одинаковое. ноthread-loader
Конфигурация проста.
5. Включите многопроцессорное сжатие JS
Хотя многиеwebpack
В статье по оптимизации будет упомянута оптимизация многопроцессорного сжатия, будь тоwebpack-parallel-uglify-plugin
илиuglifyjs-webpack-plugin
настроитьparallel
. Но тут я хочу сказать, эти плагины отдельно устанавливать не нужно, они не сделают вашWebpack
Улучшения скорости сборки.
токWebpack
По умолчанию используетсяTerserWebpackPlugin
, многопроцессорность и кеширование включены по умолчанию, вы можете увидеть это в своем проекте при сборкеterser
Кэш-файлnode_modules/.cache/terser-webpack-plugin
.
6.HardSourceWebpackPlugin
HardSourceWebpackPlugin
Предоставляет промежуточный кеш для модулей.Путь хранения по умолчанию для кеша:node_modules/.cache/hard-source
.
настроитьhard-source-webpack-plugin
, время сборки в первый раз не сильно изменилось, но во второй раз время сборки сократилось примерно на 80%.
Сначала установите зависимости:
npm install hard-source-webpack-plugin -D
Исправлятьwebpack
Конфигурация:
//webpack.config.js
var HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
module.exports = {
//...
plugins: [
new HardSourceWebpackPlugin()
]
}
Протестировано с другим более крупным проектом, настроеннымHardSourceWebpackPlugin
, время сборки сократилось с 8 с до 2 с.
В документации HardSourceWebpackPluginПеречисляет некоторые проблемы, с которыми вы можете столкнуться, и способы их решения, такие как сбой горячего обновления, некоторые конфигурации не вступают в силу и т. д.
7.noParse
Если некоторые сторонние модули не имеют версии спецификации AMD/CommonJS, вы можете использоватьnoParse
идентифицировать модуль, чтобыWebpack
Эти модули будут введены, но не преобразованы и не проанализированы, тем самым улучшаяWebpack
построить производительность, например:jquery
,lodash
.
noParseЗначением атрибута является регулярное выражение илиfunction
.
//webpack.config.js
module.exports = {
//...
module: {
noParse: /jquery|lodash/
}
}
мой текущийwebpack-optimize
проект, не используетсяjquery
илиlodash
.
Поэтому создайте новый тест проекта и вводите толькоjquery
а такжеloadsh
, затем настройтеnoParse
и не настроенnoParse
, соответственно, для построения времени сравнения.
настроитьnoParse
Раньше для сборки требовалось2392ms
. настроенnoParse
После этого для сборки требуется1613ms
. Если вы используете сторонние зависимости, которые не нужно разрешать, то настройтеnoParse
Понятно, что будет оптимизация.
8.resolve
resolve
настроитьwebpack
Как найти файл, соответствующий модулю. Предположим, мы уверены, что модули все из корневого каталогаnode_modules
Найдите в, мы можем настроить:
//webpack.config.js
const path = require('path');
module.exports = {
//...
resolve: {
modules: [path.resolve(__dirname, 'node_modules')],
}
}
Важно помнить, что если вы настроите вышеуказанноеresolve.moudles
, может быть проблема, например, есть ещеnode_modules
каталог, то он появится, соответствующий файл, очевидно, есть, но выдается сообщение, что он не может быть найден. Поэтому я лично не рекомендую настраивать это. Если другие коллеги не знакомы с этой конфигурацией, они будут сбиты с толку, когда столкнутся с этой проблемой.
Кроме того,resolve
изextensions
конфигурация, по умолчанию['.js', '.json']
, если вы настраиваете его, не забудьте поставить наиболее часто встречающийся суффикс первым и контролировать длину списка, чтобы уменьшить количество попыток.
Этот проект небольшой, поэтому эффект оптимизации здесь не очевиден при тестировании.
9.IgnorePlugin
webpack
Встроенный плагин, роль которого заключается в игнорировании каталога, указанного сторонним пакетом.
Например:moment
(версия 2.24.0) упакует весь локализованный контент и основные функции вместе, мы можем использоватьIgnorePlugin
Игнорируйте локализованный контент при упаковке.
//webpack.config.js
module.exports = {
//...
plugins: [
//忽略 moment 下的 ./locale 目录
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
]
}
При использовании, если нам нужно указать язык, нам нужно вручную импортировать языковой пакет, например, импортировать китайский языковой пакет:
import moment from 'moment';
import 'moment/locale/zh-cn';// 手动引入
index.js
только импортmoment
, упакованныйbundle.js
размер263KB
, если настроеноIgnorePlugin
, вводится отдельноmoment/locale/zh-cn
, размер собранного пакета55KB
.
10.externals
Мы можем хранить некоторые файлы JS вCDN
вверх (уменьшениеWebpack
упакованныйjs
объем), вindex.html
прошедший<script>
Введение этикетки, например:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="root">root</div>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
</body>
</html>
Надеемся, что при использовании еще возможно пройтиimport
ссылаться (например,import $ from 'jquery'
), И надеюсьwebpack
Он не будет упакован и может быть настроен на этом этапе.externals
.
//webpack.config.js
module.exports = {
//...
externals: {
//jquery通过script引入之后,全局中即有了 jQuery 变量
'jquery': 'jQuery'
}
}
11.DllPlugin
Иногда, если все файлы JS сгруппированы в один файл JS, окончательный сгенерированный файл JS будет очень большим.В настоящее время мы должны рассмотреть возможность разделенияbundles
.
DllPlugin
а такжеDLLReferencePlugin
можно разделитьbundles
И может значительно улучшить скорость строительства,DllPlugin
а такжеDLLReferencePlugin
обеwebpack
встроенный модуль.
Мы используемDllPlugin
Компилировать редко обновляемые библиотеки, а когда версия этих зависимостей не меняется, перекомпилировать не нужно. мы создаем новыйwebpack
config специально для компиляции библиотек динамической компоновки, например, с именем:webpack.config.dll.js
, здесь мы будемreact
а такжеreact-dom
Упакован отдельно в динамическую библиотеку.
//webpack.config.dll.js
const webpack = require('webpack');
const path = require('path');
module.exports = {
entry: {
react: ['react', 'react-dom']
},
mode: 'production',
output: {
filename: '[name].dll.[hash:6].js',
path: path.resolve(__dirname, 'dist', 'dll'),
library: '[name]_dll' //暴露给外部使用
//libraryTarget 指定如何暴露内容,缺省时就是 var
},
plugins: [
new webpack.DllPlugin({
//name和library一致
name: '[name]_dll',
path: path.resolve(__dirname, 'dist', 'dll', 'manifest.json') //manifest.json的生成路径
})
]
}
существуетpackage.json
изscripts
Добавить в:
{
"scripts": {
"dev": "NODE_ENV=development webpack-dev-server",
"build": "NODE_ENV=production webpack",
"build:dll": "webpack --config webpack.config.dll.js"
},
}
воплощать в жизньnpm run build:all
, можно увидетьdist
Каталог выглядит следующим образом, причина, по которой динамическая библиотека размещена отдельноdll
каталог, в основном для использованияCleanWebpackPlugin
Динамические библиотеки удобнее отфильтровывать.
dist
└── dll
├── manifest.json
└── react.dll.9dcd9d.js
manifest.json
раньше позволялDLLReferencePlugin
Сопоставьте со связанными зависимостями.
Исправлятьwebpack
Основной файл конфигурации:webpack.config.js
Конфигурация:
//webpack.config.js
const webpack = require('webpack');
const path = require('path');
module.exports = {
//...
devServer: {
contentBase: path.resolve(__dirname, 'dist')
},
plugins: [
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, 'dist', 'dll', 'manifest.json')
}),
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: ['**/*', '!dll', '!dll/**'] //不删除dll目录
}),
//...
]
}
использоватьnpm run build
построить, вы можете видетьbundle.js
громкость сильно уменьшается.
Исправлятьpublic/index.html
файл, в который вы импортируетеreact.dll.js
<script src="/dll/react.dll.9dcd9d.js"></script>
скорость наращивания
объем пакета
12. Извлеките общедоступный код
Извлечение общего кода предназначено для многостраничных приложений.Если на нескольких страницах представлены некоторые общие модули, эти общие модули можно извлечь и упаковать отдельно. Общий код нужно загрузить только один раз и кэшировать, избегая повторных загрузок.
Не должно быть разницы в настройке одностраничных приложений и многостраничных приложений путем извлечения публичного кода, все они настраиваются вoptimization.splitChunks
середина.
//webpack.config.js
module.exports = {
optimization: {
splitChunks: {//分割代码块
cacheGroups: {
vendor: {
//第三方依赖
priority: 1, //设置优先级,首先抽离第三方模块
name: 'vendor',
test: /node_modules/,
chunks: 'initial',
minSize: 0,
minChunks: 1 //最少引入了1次
},
//缓存组
common: {
//公共模块
chunks: 'initial',
name: 'common',
minSize: 100, //大小超过100个字节
minChunks: 3 //最少引入了3次
}
}
}
}
}
Даже одностраничные приложения также могут использовать эту конфигурацию.Например, если упакованный bundle.js слишком велик, мы можем упаковать некоторые зависимости в библиотеки динамической компоновки, а затем удалить оставшиеся сторонние зависимости. Это может эффективно уменьшить размер bundle.js. Конечно, можно продолжать извлекать публичные модули бизнес-кода, здесь из-за того, что в моем проекте мало исходников, нет настройки.
runtimeChunk
runtimeChunk
Эффект должен включатьchunk
Список отображений изmain.js
извлечено изsplitChunk
не забудьте настроитьruntimeChunk
.
module.exports = {
//...
optimization: {
runtimeChunk: {
name: 'manifest'
}
}
}
Окончательный построенный файл будет генерироватьmanifest.js
.
Дальнейшая оптимизация с помощью webpack-bundle-analyzer
делаетwebpack
При построении оптимизацийvendor
Я играл более 1М,react
а такжеreact-dom
Упакован в DLL.
Следовательно, необходимо использоватьwebpack-bundle-analyzer
Проверьте, какие сумки больше.
Сначала установите зависимости:
npm install webpack-bundle-analyzer -D
Он также очень прост в использовании, изменим нашу конфигурацию:
//webpack.config.prod.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const merge = require('webpack-merge');
const baseWebpackConfig = require('./webpack.config.base');
module.exports = merge(baseWebpackConfig, {
//....
plugins: [
//...
new BundleAnalyzerPlugin(),
]
})
npm run build
Build, он будет включен по умолчанию:http://127.0.0.1:8888/
, вы можете увидеть объем каждого пакета:
дальше кvendor
расколоть,vendor
разделить на 4 (используяsplitChunks
можно разделить).
module.exports = {
optimization: {
concatenateModules: false,
splitChunks: {//分割代码块
maxInitialRequests:6, //默认是5
cacheGroups: {
vendor: {
//第三方依赖
priority: 1,
name: 'vendor',
test: /node_modules/,
chunks: 'initial',
minSize: 100,
minChunks: 1 //重复引入了几次
},
'lottie-web': {
name: "lottie-web", // 单独将 react-lottie 拆包
priority: 5, // 权重需大于`vendor`
test: /[\/]node_modules[\/]lottie-web[\/]/,
chunks: 'initial',
minSize: 100,
minChunks: 1 //重复引入了几次
},
//...
}
},
},
}
Перестройте, и результат будет выглядеть так:
13. Оптимизация самого вебпака
tree-shaking
Если вы используете ES6import
синтаксис, то в рабочей среде неиспользуемый код будет автоматически удален.
//math.js
const add = (a, b) => {
console.log('aaaaaa')
return a + b;
}
const minus = (a, b) => {
console.log('bbbbbb')
return a - b;
}
export {
add,
minus
}
//index.js
import {add, minus} from './math';
add(2,3);
В финальном коде сборкиminus
Функции не упакованы.
продвижение масштаба хостинга
Продвижение переменных может уменьшить количество объявлений некоторых переменных. В производственной среде он включен по умолчанию.
Также будьте осторожны при тестировании.speed-measure-webpack-plugin
а такжеHotModuleReplacementPlugin
Нельзя использовать одновременно, иначе будет сообщено об ошибке:
Оптимизация конфигурации Babel
если ты правbabel
Если вы не знакомы с ним, вы можете прочитать эту статью:Знания Babel7, которые нельзя упустить.
без настройки@babel/plugin-transform-runtime
час,babel
будет использовать небольшую вспомогательную функцию для достижения чего-то вроде_createClass
и другие общедоступные методы. По умолчанию он будет введен (inject
) в каждый файл, который в этом нуждается. Но в результате этого размер построенного JS становится больше.
Нам также не нужноjs
внедрить вспомогательную функцию в , чтобы мы могли использовать@babel/plugin-transform-runtime
,@babel/plugin-transform-runtime
является многоразовымBabel
Добавлены помощники для сохранения плагинов размера кода.
Поэтому мы можем.babelrc
увеличить в@babel/plugin-transform-runtime
Конфигурация.
{
"presets": [],
"plugins": [
[
"@babel/plugin-transform-runtime"
]
]
}
Выше приведены некоторые из оптимизаций, которые я использовал до сих пор.Если у вас есть лучший метод оптимизации, оставьте сообщение в области комментариев, спасибо за чтение.
После прочтения этой статьи пришло время заняться строительными лесами:[Основы пользовательского интерфейса среднего и продвинутого уровня] Научат вас строить строительные леса касанием рук.
наконец
Если эта статья была вам полезна, пожалуйста, поставьте лайк этой статье.
Обратите внимание на публичный аккаунт
Справочная документация:
- Некоторые основные методы оптимизации веб-пакетов
- Модуль
- IgnorePlugin
- DllPlugin
- Ускорьте сборку проекта с помощью DllPlugin от Webpack
- Используйте ХэппиПак
- webapck4 извлекает общий модуль "SplitChunksPlugin"
- Оптимизация webpack (4): hard-source-webpack-plugin, альтернатива конфигурации webpack DllPlugin