в предыдущем постеПолный разбор конфигурации WebpackПредставлены некоторые базовые способы использования загрузчиков и плагинов в Webpack.Когда используется больше загрузчиков и плагинов, проект будет занимать все больше и больше времени, поэтому на этот раз мы продолжим изучать, как оптимизировать конфигурацию веб-пакета, чтобы сделать наш проект бежать быстрее время короче.
В этой статье мы узнаем об оптимизированной конфигурации Webpack с четырех аспектов: сужение диапазона поиска файлов, сокращение связанных файлов, кэширование и многопроцессорность.
Сузьте поиск файлов
Webpack начнет с записи Entry, проанализирует оператор модуля импорта в файле, а затем проанализирует его рекурсивно; каждый раз, когда он сталкивается с грамматикой импорта, он будет делать две вещи:
- Найдите местоположение импортированного модуля, например.
require('vue')
просто импортировать/node_modules/vue/dist/vue.runtime.common.js
документ - Импортированные модули анализируются соответствующим загрузчиком, например, импортированный js вызовет babel-loader для преобразования кода
Когда в проекте всего несколько файлов, процесс парсинга файлов занимает всего несколько сотен миллисекунд, однако по мере увеличения масштаба проекта парсинг файлов будет занимать все больше и больше времени, поэтому мы сужаем рамки наших поисковых модулей через настройку вебпака
Оптимизация конфигурации загрузчика
В предыдущей статье мы познакомились с использованиемinclude/exclude
Включить/исключить файлы в node_modules.
{
rules: [{
test: /\.js$/,
use: {
loader: 'babel-loader'
},
// exclude: /node_modules/,
include: [path.resolve(__dirname, 'src')]
}]
}
include
Указывает, какие файлы в каталоге должны быть загрузчиком babel,exclude
Указывает, какие файлы в каталоге не должны быть загрузчиком babel. Это связано с тем, что при внедрении сторонних модулей многие модули уже упакованы и не нуждаются в обработке, например, vue, jQuery и т. д.; если не установленоinclude/exclude
Он будет обработан загрузчиком, что увеличит время упаковки.
Оптимизация конфигурации module.noParse
Если некоторые сторонние модули не используют спецификацию AMD/CommonJs, вы можете использоватьnoParse
чтобы пометить этот модуль, чтобы когда Webpack импортирует модуль, он не анализировал и не преобразовывал, повышая скорость построения Webpack; noParse может принимать регулярное выражение или функцию:
{
module: {
//noParse: /jquery|lodash|chartjs/,
noParse: function(content){
return /jquery|lodash|chartjs/.test(content)
}
}
}
Для некоторых библиотек, таких как jQuery, lodash, chartjs и т. д., они огромны и не принимают модульных стандартов, поэтому мы можем не анализировать их.
Примечание: неразобранные файлы модулей не должны содержать
require
,import
Оператор равного модуля
После многих попыток упаковки производительность упаковки может быть улучшена примерно на 10–20 %; полный код этого примераdemo,
Оптимизация конфигурации resolve.modules
modules используется, чтобы сообщить Webpack, в каких каталогах искать модули, на которые ссылаются.Значение по умолчанию:["node_modules"]
, то есть в./node_modules
Найдите модуль, если не можете найти, перейдите../node_modules
, и так далее.
В нашем коде также есть большое количество модулей, которые зависят от других модулей и вводятся ими.Поскольку расположение этих модулей не является фиксированным, путь иногда бывает очень длинным, напримерimport '../../src/components/button'
,import '../../src/utils'
; На этом этапе мы можем использовать модули для оптимизации
{
resolve: {
modules: [
path.resolve(__dirname, "src"),
path.resolve(__dirname, "node_modules"),
"node_modules",
],
},
}
Таким образом, мы можем простоimport 'components/button'
,import 'utils'
Импорт, webpack будет иметь приоритет отsrc
искать в каталоге
Оптимизация конфигурации resolve.alias
alias сопоставляет путь исходного импортированного модуля с новым путем импорта, создавая псевдоним import или require; он иresolve.modules
Разница в том, что его функция состоит в том, чтобы заменить предыдущий путь псевдонимом, а не пропустить его; преимущество этого в том, что веб-пакет будет напрямую переходить в каталог, соответствующий псевдониму, для поиска модуля, сокращая время поиска.
{
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
},
},
}
чтобы мы могли пройтиimport Buttom from '@/Button'
Давайте познакомимся с компонентами, мы можем не только устанавливать псевдонимы для наших собственных модулей, но и устанавливать псевдонимы для сторонних модулей:
{
resolve: {
alias: {
'vue$': isDev ? 'vue/dist/vue.runtime.js' : 'vue/dist/vue.runtime.min.js',
},
},
}
мы вimport Vue from 'vue'
, webpack поможет нам импортировать соответствующие файлы в dist-файле пакета зависимостей vue, сократив время на поиск package.json.
Оптимизация конфигурации resolve.mainFields
mainFields используется, чтобы сообщить webpack, какое поле в стороннем модуле использовать для импорта модуля; каждый сторонний модуль будет иметь одно поле.package.json
Файл используется для описания некоторых свойств этого модуля, таких как имя модуля (имя), номер версии (версия), автор (аутентификация) и т. д.; наиболее важным из которых является наличие нескольких специальных полей, используемых для указания веб-пакета расположение импортированного файла. Причина наличия нескольких полей заключается в том, что некоторые модули могут использоваться в нескольких средах одновременно, и каждая среда может использовать другой файл.
Значение по умолчанию для mainFields и текущая конфигурация веб-пакета.target
Свойства, связанные с:
- если цель
webworker
илиweb
(по умолчанию), значение mainFields по умолчанию равно["browser", "module", "main"]
- Если цель другая (включая узел), значение mainFields по умолчанию равно
["module", "main"]
Это означает, что когда мыrequire('vue')
В то время webpack сначала ищет поле браузера под vue, затем ищет поле модуля, если оно не найдено, и, наконец, ищет основное поле.
Для уменьшения шагов поиска, при указании поля описания входного файла стороннего модуля, мы можем установить это поле как можно меньше, обычно сторонние модули используютmain
поле, поэтому мы можем настроить его следующим образом:
{
resolve: {
mainFields: ["main"],
}
}
Оптимизация конфигурации resolve.extensions
Поле расширений используется для автоматического ввода суффикса, чтобы попытаться сопоставить соответствующий файл при импорте модуля.Его значение по умолчанию:
{
resolve: {
extensions: ['.js', '.json']
}
}
То есть мыrequire('./utils')
, Webpack первые совпаденияutils.js
, если он не может совпасть, попробуйте сопоставитьutils.json
, если он все еще не найден, будет сообщено об ошибке.
следовательноextensions
Чем длиннее массив или чем позже файл с правильным суффиксом, тем больше раз количество совпадений будет трудоемким, поэтому мы можем оптимизировать из следующих пунктов:
- Массив расширений должен быть как можно меньше, а суффиксы файлов, которых нет в проекте, не должны быть перечислены.
- Файловые суффиксы, которые появляются чаще, имеют приоритет на переднем плане.
- При импорте файлов в код старайтесь указывать суффикс имени, чтобы избежать поиска
Полный код приведенного выше примераdemo.
Уменьшить файлы пакета
В нашем проекте неизбежно будут внедрены сторонние модули.При упаковке вебпака сторонние модули также будут упакованы в бандлы в качестве зависимостей, что увеличит размер упакованного файла и увеличит временные затраты.Если эти модули с ним можно обращаться разумно, его можно улучшить Высокая производительность веб-пакета.
Извлечь общедоступный код
Наш проект обычно имеет несколько страниц или многостраничных модулей (одна страница), и между несколькими страницами обычно есть общие функции или сторонние модули.Упаковка этих модулей на каждой странице вызовет следующие проблемы:
- Многократная загрузка ресурсов тратит впустую пользовательский трафик
- Каждая страница загружает много ресурсов, а отображение первого экрана медленное
До Webpack4 для извлечения общего кода использовался плагин CommonsChunkPlugin, но были следующие проблемы
- Когда выходной блок будет импортирован, он будет содержать повторяющийся код.
- Невозможно оптимизировать асинхронные фрагменты
Представлен Webpack4SplitChunksPlugin
Плагин извлекает общие модули, за счет встроенной функции webpack4 его не нужно устанавливать отдельно, черезoptimization.splitChunks
Вы можете настроить его.Параметры конфигурации по умолчанию, указанные официальным лицом, следующие:
module.exports = {
optimization: {
splitChunks: {
// 代码分割时默认对异步代码生效,all:所有代码有效,inital:同步代码有效
chunks: 'async',
// 代码分割最小的模块大小,引入的模块大于 20000B 才做代码分割
minSize: 20000,
// 代码分割最大的模块大小,大于这个值要进行代码分割,一般使用默认值
maxSize: 0,
// 引入的次数大于等于1时才进行代码分割
minChunks: 1,
// 最大的异步请求数量,也就是同时加载的模块最大模块数量
maxAsyncRequests: 30,
// 入口文件做代码分割最多分成 30 个 js 文件
maxInitialRequests: 30,
// 文件生成时的连接符
automaticNameDelimiter: '~',
enforceSizeThreshold: 5000,
cacheGroups: {
vendors: {
// 位于node_modules中的模块做代码分割
test: /[\\/]node_modules[\\/]/,
// 根据优先级决定打包到哪个组里,例如一个 node_modules 中的模块进行代码
priority: -10
},
// 既满足 vendors,又满足 default,那么根据优先级会打包到 vendors 组中。
default: {
// 没有 test 表明所有的模块都能进入 default 组,但是注意它的优先级较低。
// 根据优先级决定打包到哪个组里,打包到优先级高的组里。
priority: -20,
//如果一个模块已经被打包过了,那么再打包时就忽略这个上模块
reuseExistingChunk: true
}
}
}
}
};
Мы представили vue.js, axios.js и общедоступный служебный функциональный модуль utils.js на трех страницах главной страницы, списка и подробностей соответственно; сначала мы извлекли используемые сторонние модули в отдельный файл, который содержит базовую операционную среду. проекта, обычно называемогоvendors.js
; После извлечения стороннего модуля мы извлекаем публичный код, от которого зависит каждая страница, и помещаем его вcommon.js
середина.
module.exports = {
optimization: {
splitChunks: {
chunks: 'initial',
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: 10,
name: 'vendors'
},
common: {
test: /[\\/]src[\\/]/,
priority: 5,
name: 'common'
}
}
}
}
}
Иногда проект зависит от большего количества модулей,vendors.js
Файл будет очень большим, и мы можем дополнительно разбить его на модули:
{
//省略其他配置
cacheGroups: {
//涉及vue的模块
vue: {
test: /[\\/]node_modules[\\/](vue|vuex|vue-router)/,
priority: 10,
name: 'vue'
},
//其他模块
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: 9,
name: 'vendors'
},
common: {
test: /[\\/]src[\\/]/,
priority: 5,
name: 'common'
}
}
}
Динамически связывать DllPlugin
DLL является аббревиатурой от Dynamic-Link Library.Дети, знакомые с системой Windows, часто могут видеть на компьютере файлы с расширением dll.Иногда компьютер выдает предупреждения о том, что на компьютере отсутствуют некоторые dll-файлы;DLL изначально использовалась для экономить место на диске и в памяти, необходимое для приложения, когда несколько программ используют одну и ту же библиотеку функций, DLL может уменьшить дублирование загрузки кода на диск и в память, что полезно для повторного использования кода.
Идея DLL также представлена в Webpack, который извлекает используемые нами модули и упаковывает их в отдельную библиотеку динамической компоновки.В динамической библиотеке может быть несколько модулей; когда мы используем ее на нескольких страницах. не упаковывается повторно, он напрямую импортирует модуль в библиотеку динамической компоновки.
Webpack интегрирует поддержку динамически подключаемых библиотек, в основном используя два плагина:
- DllPlugin: создать файл библиотеки динамической компоновки
- DllReferencePlugin: добавьте упакованный файл библиотеки динамической компоновки в основную конфигурацию.
Сначала мы используем DllPlugin для создания файла динамической библиотеки и создаем новый в рамках проекта.webpack.dll.js
документ:
const path = require("path");
const webpack = require("webpack");
module.exports = {
mode: "production",
entry: {
vue: ["vue", "vuex", "vue-router"],
vendor: ["dayjs", "axios", "mint-ui"],
},
output: {
path: path.resolve(__dirname, "public/vendor"),
// 指定文件名
filename: "[name].dll.js",
//暴露全局变量的名称
library: "[name]_dll_lib",
},
plugins: [
new webpack.DllPlugin({
path: path.join(__dirname, "public", "vendor", "[name].manifest.json"),
name: "[name]_dll_lib",
}),
],
};
здесьentry
Задается несколько записей, и каждая запись также имеет несколько файлов модулей; затем вpackage.json
добавить команду упаковки
{
"scripts":{
"build:dll": "webpack --config=webpack.dll.js"
}
}
воплощать в жизньnpm run build:dll
После этого мы/public/vendor
Файлы нашей упакованной динамической библиотеки получаются в каталоге:
├── vendor.dll.js
├── vendor.manifest.json
├── vue.dll.js
└── vue.manifest.json
Сгенерированный файл пакета назван в честь двух имен записей.В качестве примера возьмем vue, взглянитеvue.dll.js
Содержание:
var vue_dll_lib =
/******/ (function(modules) {
// 省略webpackBootstrap代码
/******/ })
/******/ ({
/***/ "./node_modules/vue-router/dist/vue-router.esm.js":
/***/ (function(module, exports, __webpack_require__) {
//省略vue-router模块代码
/***/ }),
/***/ "./node_modules/vue/dist/vue.runtime.esm.js":
/***/ (function(module, exports, __webpack_require__) {
//省略vue模块代码
/***/ }),
/***/ "./node_modules/vuex/dist/vuex.esm.js":
/***/ (function(module, exports, __webpack_require__) {
//省略vuex模块代码
/***/ }),
/******/ });
Видно, что библиотека динамической компоновки содержит весь код импортированного модуля, который существует в объекте и на который ссылается путь к модулю как имя ключа, и выставлен на глобальную через vue_dll_lib, используется vue.manifest.json чтобы описать, какие модули включены в файл библиотеки динамической компоновки:
{
"name": "vue_dll_lib",
"content": {
"./node_modules/vue-router/dist/vue-router.esm.js": {
"id": "./node_modules/vue-router/dist/vue-router.esm.js",
"buildMeta": {}
},
"./node_modules/vue/dist/vue.runtime.esm.js": {
"id": "./node_modules/vue/dist/vue.runtime.esm.js",
"buildMeta": {}
},
"./node_modules/vuex/dist/vuex.esm.js": {
"id": "./node_modules/vuex/dist/vuex.esm.js",
"buildMeta": {}
},
}
}
manifest.json описывает, какие модули содержит соответствующий файл js, и имя ключа (идентификатор) соответствующего модуля, чтобы мы могли импортировать библиотеку динамической компоновки в качестве внешней ссылки на странице шаблона, и когда Webpack анализирует соответствующий модуль, он передает глобальную переменную для получения модуля:
<!-- public/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<!-- 引入动态链接库 -->
<script src="./vendor/vendor.dll.js"></script>
<script src="./vendor/vue.dll.js"></script>
</body>
</html>
Наконец, когда мы собирались, мы прошлиDllReferencePlugin
Импортируйте библиотеку динамической компоновки в основную конфигурацию:
//webpack.config.js
{
plugins: [
new webpack.DllReferencePlugin({
context: path.join(__dirname),
manifest: require('./public/vendor/vendor.manifest.json')
}),
new webpack.DllReferencePlugin({
context: path.join(__dirname),
manifest: require('./public/vendor/vue.manifest.json')
}),
]
}
Примечание. Библиотека динамической компоновки упакована в
/public/vendor
каталог, вам также необходимо пройтиCopyWebpackPlugin
Плагин копирует его в сгенерированный каталог, в противном случае возникнет ошибка сбоя ссылки; упаковка файла библиотеки динамической компоновки должна быть выполнена только один раз, если только модуль не будет обновлен или новый модуль не будет введен позже.
Внедрение библиотеки динамической компоновки может поместить некоторые редко обновляемые модули проекта во внешние файлы.Когда мы снова упакуем код логики страницы, мы обнаружим, что скорость построения значительно улучшилась, примерно на 30%~40%.Соответствующий код вdemo10.
externals
Когда мы упаковываем проект, некоторые сторонние библиотеки будут импортированы из CDN (например, jQuery и т. д.) Если он слишком раздут, чтобы снова упаковать проект в бандле, мы можем настроитьexternals
Исключите эти библиотеки из упаковки.
{
externals: {
'jquery': "jQuery",
'react': 'React',
'react-dom': 'ReactDOM',
'vue': 'Vue'
}
}
Это означает, что когда мы встретимсяrequire('jquery')
, разыменование глобальных переменныхjQuery
, то же самое верно для нескольких других пакетов, таким образом jquery, react, vue и react-dom удаляются из бандла при упаковке.Полный код этого примераdemo.
Tree Shaking
Tree Shaking сначала был реализован с помощью rollup, а позже эту функцию реализовал webpack2; Tree Shaking буквально означает встряхивание дерева. Хотя некоторые листья еще висят на дереве, возможно, оно погибло. Эти мертвые листья удаляются.
То же самое и в нашем проекте, мы не используем все модули файла, но webpack все равно упакует весь файл, а код, который никогда не использовался в файле, является «мертвым кодом», в данном случае это используетсяTree Shaking
Помогите нам избавиться от этих неиспользуемых модулей кода.
Например, мы определяемutils.js
Файл экспортирует множество модулей инструментов, а затем вindex.js
Только определенные модули упоминаются в:
//utils.js
var toString = Object.prototype.toString;
export function isArray(val) {
return toString.call(val) === '[object Array]';
}
export function isFunction(val) {
return toString.call(val) === '[object Function]';
}
export function isDate(val) {
return toString.call(val) === '[object Date]';
}
//index.js
import { isArray } from './utils'
isArray()
Хотим упаковать только в кодisArray
функцию в бандл; следует отметить, что для того, чтобы Tree Shaking вступила в силу, нам нужно использовать модульный синтаксис ES6, потому что синтаксис модуля ES6 — это статически загруженный модуль, который имеет следующие характеристики:
- Статическая загрузка модулей, что более эффективно, чем метод загрузки модулей CommonJS.
- Модули ES6 загружаются во время компиляции, что делает возможным статический анализ для дальнейшего расширения синтаксиса JS.
еслиrequire
, чтобы определить модуль во время выполнения, то нельзя будет проанализировать, доступен ли модуль, только анализ во время компиляции не повлияет на состояние во время выполнения.
Есть еще одна проблема после использования модулей ES6, потому что наш код обычно компилируется с помощью babel, а предустановка babel по умолчанию компилирует любой тип модуля в Commonjs, поэтому нам также нужно изменить.babelrc
Конфигурационный файл:
{
"presets": [
[
"@babel/preset-env",
{
//添加modules:false
"modules": false
}
]
]
}
После настройки babel нам нужно сначала позволить webpack идентифицировать «мертвый код»:
{
//其他配置
optimization: {
usedExports: true,
sideEffects: true,
}
}
После запуска команды упаковки, когда мы открыли выходной пакетный файл, мы обнаружили, что хотя некоторый «мертвый код» все еще существует, ноunused harmony export
логотип
/* unused harmony export isFunction */
/* unused harmony export isDate */
var toString = Object.prototype.toString;
function isFunction(val) {
return toString.call(val) === '[object Function]';
}
function isDate(val) {
return toString.call(val) === '[object Date]';
}
Хотя webpack указывает нам, какие функции не используются, нам все же нужно устранить их с помощью плагинов, потому чтоuglifyjs-webpack-plugin
Синтаксис ES6 не поддерживается, здесь мы используемterser-webpack-plugin
плагин для его замены:
const TerserJSPlugin = require("terser-webpack-plugin");
module.exports = {
optimization: {
usedExports: true,
sideEffects: true,
minimize: true,
minimizer: [
new TerserJSPlugin({
cache: true,
parallel: true,
sourceMap: false,
}),
],
}
}
Таким образом, мы обнаруживаем, что в упакованном файле нет лишнего кода.
Примечание. Tree Shaking включено по умолчанию в рабочей среде.
Для некоторых из наших часто используемых сторонних модулей мы также можем реализовать встряхивание дерева;lodash
Например, у него очень много функций в целом пакете, но не все функции используются нами, поэтому нам также необходимо исключить код, который им не используется.
//index.js
import { chunk } from 'lodash'
console.log(chunk([1,2,3,4], 2))
После упаковки обнаружил, что размер пакета еще может достигать 70+кб, если ссылаться только на чанк, то он не должен быть таким большим, открываем его/node_modules/lodash/index.js
Было обнаружено, что он по-прежнему использовал режим require для импорта и экспорта модулей, что приводило к сбою Tree Shaking; сначала мы установили модульную версию lodash для ES6:npm i -S lodash-es
, а затем измените пакет импорта:
//index.js
import { chunk } from 'lodash-es'
console.log(chunk([1,2,3,4], 2))
Таким образом, пакет пакетов, который мы генерируем, намного меньше; полный код этого примераdemo.
тайник
Мы знаем, что webpack будет вызывать разные загрузчики для разбора разных файлов, а процесс разбора также является самым ресурсоемким процессом; каждый раз, когда мы меняем код, мы модифицируем лишь несколько файлов в проекте, а количество изменений в большинстве файлов в проекте не так часто, то если мы кешируем результат парсинга файла, то в следующий раз, когда мы найдем тот же файл, нам нужно только прочитать кеш, что может значительно улучшить производительность парсинга.
cache-loader
Кэш-загрузчик может кэшировать результаты, полученные некоторыми загрузчиками, которые потребляют большую часть производительности на диске.Когда тот же код снова упаковывается в следующий раз, кеш может быть прочитан напрямую, чтобы снизить потребление производительности.
Примечание. Сохранение и чтение кеша также приведет к дополнительной нагрузке на производительность, поэтому cache-loader подходит для загрузчиков, которые потребляют много производительности, в противном случае это увеличит потребление производительности.
Использование cache-loader также очень простое.После установки его можно добавить перед загрузчиком, который необходимо кэшировать (потому что порядок загрузки загрузчика обратный).Например, нам нужно датьbabel-loader
Добавить кеш:
{
//省略其他代码
rules: [
{
test: /\.js/,
use: [
{
loader: 'cache-loader'
},
{
loader: "babel-loader",
},
],
},
],
}
Однако мы обнаружили, что скорость первой упаковки существенно не изменилась и может быть даже медленнее, чем у оригинальной упаковки; в то же время существует больше/node_modules/.cache/cache-loader/
Эта директория, имя - файл кеша, мы продолжаем запаковывать, следующая диаграмма фиксирует время, которое я потратил несколько раз на запаковку:
Мы обнаружили, что первое время упаковки было примерно таким же, но во второй раз, когда мы начали кэшировать файлы, это стало играть важную роль, что напрямую сократило время на 75%.
В дополнение к использованию cache-loader, babel-loader также обеспечивает функциональность кэширования черезcacheDirectory
Чтобы настроить:
{
rules: [
{
test: /\.js/,
use: [
{
loader: "babel-loader",
options: {
cacheDirectory: true
}
},
],
},
],
}
существует/node_modules/.cache/babel-loader
Есть также больше файлов кеша. После сравнения двух результатов использования, повышение производительности cache-loader стало еще лучше; полный код этого примераdemo.
HardSourceWebpackPlugin
HardSourceWebpackPlugin также может обеспечивать кэширование модулей и соглашаться на кэширование файлов на диске.
сначала черезnpm i -D hard-source-webpack-plugin
чтобы установить плагин и добавить плагин в конфигурацию:
var HardSourceWebpackPlugin =
require('hard-source-webpack-plugin');
module.exports = {
plugins: [
new HardSourceWebpackPlugin()
]
}
Как правило, кеш HardSourceWebpackPlugin по умолчанию находится в/node_modules/.cache/hard-source/[hash]
каталог, мы можем установить его каталог кеша и когда создать новый хэш кеша.
module.exports = {
plugins: [
new HardSourceWebpackPlugin({
//设置缓存目录的路径
//相对路径或者绝对路径
cacheDirectory: 'node_modules/.cache/hard-source/[confighash]',
//构建不同的缓存目录名称
//也就是cacheDirectory中的[confighash]值
configHash: function(webpackConfig) {
return require('node-object-hash')({sort: false}).hash(webpackConfig);
},
//环境hash
//当loader、plugin或者其他npm依赖改变时进行替换缓存
environmentHash: {
root: process.cwd(),
directories: [],
files: ['package-lock.json', 'yarn.lock'],
},
//自动清除缓存
cachePrune: {
//缓存最长时间(默认2天)
maxAge: 2 * 24 * 60 * 60 * 1000,
//所有的缓存大小超过size值将会被清除
//默认50MB
sizeThreshold: 50 * 1024 * 1024
},
})
]
}
При многократных попытках упаковки было обнаружено, что это может сэкономить около 90% времени; полный код этого примераdemo.
мультипрогресс
мы вв цикле событийКак уже упоминалось, js — это однопоточный язык, и только один поток обрабатывает задачи в одной и той же строке событий, поэтому, когда веб-пакет анализирует файлы JS, CSS, изображения или шрифты, ему необходимо анализировать и компилировать один за другим. задачи одновременно; мы можем использовать плагины для разделения задач на несколько подпроцессов для одновременного выполнения, а затем отправлять результаты в основной процесс после обработки подпроцессов.
happypack
Happypack автоматически поможет нам декомпозировать задачи и управлять процессами.Также из названия видно, что это плагин, который может принести счастье.
мы проходимnpm i -D happypack
Затем вы можете настроить его в веб-пакете:
const happypack = require("happypack");
module.exports = {
module: {
rules: [
{
test: /\.js/,
exclude: /node_modules/,
//将js文件处理给id为js的happypack实例
use: "happypack/loader?id=js",
}
],
},
plugins: [
//通过id标识当前happypack是处理什么文件的
new happypack({
id: "js",
//调用处理文件的loader,用法和rules中一致
loaders: [{
loader: "babel-loader",
},
{
loader: "eslint-loader",
},
],
}),
],
}
мы будемrules/loader
Обработка вся передается в happypack для обработки, а конкретный инстанс вызывается по id, а затем в инстансе настраивается конкретный загрузчик для обработки, в инстансе happypack кроме id и загрузчиков мы можем еще настроить количество процессов:
//共享进程池,进程池中包含5个子进程
var happyThreadPool = happypack.ThreadPool({
size: 5
});
{
plugins: [
new happypack({
id: "js",
//开启几个子进程,默认3个
threads: 3,
//共享进程池
threadPool: happyThreadPool,
//是否允许 HappyPack 输出日志
verbose: true,
loaders: [{
loader: "babel-loader",
},
{
loader: "eslint-loader",
},
],
}),
],
}
Примечание. Необходимо настроить только одно из полей threads и threadPool.
мы проходимhappypack.ThreadPool
Создается общий пул процессов, содержащий 5 подпроцессов, и каждый экземпляр happypack может обрабатывать файлы через общий пул процессов; что касается назначения процесса каждому экземпляру happypack, это может предотвратить занятие слишком большого количества бесполезных процессов; давайте упакуем и посмотрим на все занимает много времени:
Мы обнаружили, что с помощью happypack потребление времени увеличилось на 20-30%.Говорят, что многопроцессорность приносит счастье.
Поскольку наш проект недостаточно велик, а загрузка нескольких процессов также требует времени и производительности, мы будем использовать happypack, чтобы увеличить временные затраты; поэтому обычно happypack подходит для относительно больших проектов; полный код этого примераdemo.
thread-loader
Поместите загрузчик потоков перед другими загрузчиками, загрузчики после него будут работать в отдельном пуле процессов, но загрузчики, работающие в пуле процессов, имеют следующие ограничения:
- Эти загрузчики не могут генерировать новые файлы.
- Эти загрузчики не могут использовать пользовательский API загрузчика (то есть через плагины).
- Эти загрузчики не могут получить настройки параметров веб-пакета.
Следовательно, то естьMiniCssExtractPlugin.loader
Некоторые загрузчики, извлекающие CSS, не могут использовать thread-loader, как и happypack, он подходит только для больших проектов с большим количеством файлов:
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: [
"thread-loader",
"babel-loader"
]
}
]
}
}
Полный код этого примераdemo.
Автор рекомендует:
Полный анализ конфигурации Webpack (базовый)
Я пишу это резюме после интервью с 50 людьми.
Для получения дополнительной информации о внешнем интерфейсе, пожалуйста, обратите внимание на общедоступный номер【前端壹读】
.
Если вы думаете, что это хорошо написано, пожалуйста, следуйте за мнойДомашняя страница Наггетс. Для получения дополнительных статей, пожалуйста, посетитеБлог Се Сяофэй