введение
webpack
Оптимизация упаковки .
В этой статье я использую свой собственный опыт, чтобы поделиться с вами тем, как использовать некоторые инструменты анализа, плагины иwebpack
Некоторые новые функции в новой версии значительно улучшеныwebpack
Повысьте скорость упаковки и улучшите размер упаковки, научитесь анализировать узкие места и проблемы упаковки.
В этой статье демонстрируется код,Адрес склада
Анализ скорости 🏂
webpack иногда упаковывается очень медленно, и мы можем много использовать в проектеplugin
а такжеloader
, хотите знать, какая ссылка медленная, следующий плагин может вычислитьplugin
а такжеloader
кропотливый.
yarn add -D speed-measure-webpack-plugin
Конфигурация тоже очень простая, ставитеwebpack
Объект конфигурации можно обернуть:
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
const webpackConfig = smp.wrap({
plugins: [
new MyPlugin(),
new MyOtherPlugin()
]
});
Давайте взглянем на введение в проектspeed-measure-webpack-plugin
После упаковки:Как видно из рисунка выше, этот плагин в основном делает две вещи:
- Подсчитайте общее время, затраченное на весь пакет
- Анализируйте потребление времени каждым плагином и загрузчиком
знать конкретные
loader
а такжеplugin
ситуации, отнимающей много времени, мы можем «прописать правильное лекарство»
Анализ объема 🎃
Оптимизация объема после упаковки — это момент, который можно оптимизировать.Например, некоторые библиотеки сторонних компонентов слишком велики.В настоящее время необходимо подумать, найти ли альтернативы.
используется здесьwebpack-bundle-analyzer
, и это также плагин, который я чаще всего использую в своей работе.
Его можно отобразить с помощью интерактивной масштабируемой древовидной карты.webpack
Размер выходного файла. Очень удобно использовать.
Сначала установите плагин:
yarn add -D webpack-bundle-analyzer
установлен вwebpack.config.js
Простая конфигурация в:
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin({
// 可以是`server`,`static`或`disabled`。
// 在`server`模式下,分析器将启动HTTP服务器来显示软件包报告。
// 在“静态”模式下,会生成带有报告的单个HTML文件。
// 在`disabled`模式下,你可以使用这个插件来将`generateStatsFile`设置为`true`来生成Webpack Stats JSON文件。
analyzerMode: "server",
// 将在“服务器”模式下使用的主机启动HTTP服务器。
analyzerHost: "127.0.0.1",
// 将在“服务器”模式下使用的端口启动HTTP服务器。
analyzerPort: 8866,
// 路径捆绑,将在`static`模式下生成的报告文件。
// 相对于捆绑输出目录。
reportFilename: "report.html",
// 模块大小默认显示在报告中。
// 应该是`stat`,`parsed`或者`gzip`中的一个。
// 有关更多信息,请参见“定义”一节。
defaultSizes: "parsed",
// 在默认浏览器中自动打开报告
openAnalyzer: true,
// 如果为true,则Webpack Stats JSON文件将在bundle输出目录中生成
generateStatsFile: false,
// 如果`generateStatsFile`为`true`,将会生成Webpack Stats JSON文件的名字。
// 相对于捆绑输出目录。
statsFilename: "stats.json",
// stats.toJson()方法的选项。
// 例如,您可以使用`source:false`选项排除统计文件中模块的来源。
// 在这里查看更多选项:https: //github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21
statsOptions: null,
logLevel: "info"
)
]
}
Затем в инструменте командной строки введитеnpm run dev
, он запустит локальный сервер с номером порта 8888 по умолчанию:На каждом рисунке четко виден объем ассемблерного кода, сторонних библиотек.
С его помощью мы можем быть оптимизированы для соответствующего модуля, объем которого слишком велик.
Многопроцесс / многоэкземное здание 🏈
каждый знаетwebpack
работает наnode
среда, при этомnode
является однониточным.webpack
Процесс упаковкиio
Интенсивные и ресурсоемкие операции, если и то, и другоеfork
Несколько процессов обрабатывают каждую задачу параллельно, что эффективно сокращает время сборки.
Двумя наиболее часто используемыми являютсяthread-loader
а такжеHappyPack
.
Давайте взглянемthread-loader
Ну и этот тожеwebpack4
официально рекомендуется.
thread-loader
Установить
yarn add -D thread-loader
thread-loader
будет ли вашloader
помещен вworker
Запуск внутри пула для достижения многопоточных сборок.
❝возьми это
❞loader
размещены в другихloader
перед (как в примере ниже) поместите этоloader
Послеloader
будет в отдельномworker
бассейн (worker pool
) для работы.
Пример
module.exports = {
module: {
rules: [
{
test: /\.js$/,
include: path.resolve("src"),
use: [
"thread-loader",
// your expensive loader (e.g babel-loader)
]
}
]
}
}
HappyPack
Установить
yarn add -D happypack
HappyPack
может позволитьWebpack
Обрабатывайте несколько задач одновременно и играйте в многоядерные игрыCPU
Возможность декомпозиции задач на несколько подпроцессов для одновременного выполнения.После обработки подпроцессов результаты отправляются в основной процесс. Ускорьте сборку кода с помощью модели с несколькими процессами.
Пример
// webpack.config.js
const HappyPack = require('happypack');
exports.module = {
rules: [
{
test: /.js$/,
// 1) replace your original list of loaders with "happypack/loader":
// loaders: [ 'babel-loader?presets[]=es2015' ],
use: 'happypack/loader',
include: [ /* ... */ ],
exclude: [ /* ... */ ]
}
]
};
exports.plugins = [
// 2) create the plugin:
new HappyPack({
// 3) re-add the loaders you replaced above in #1:
loaders: [ 'babel-loader?presets[]=es2015' ]
})
];
Здесь следует отметить, чтоHappyPack
Автор заявил, что этот проект больше не поддерживается, это можно найти по адресуgithub
Склад видит:Автор также рекомендует использоватьwebpack
официально предоставленthread-loader
.
❝❞
thread-loader
а такжеhappypack
Для небольших проектов скорость упаковки мало влияет и может даже увеличить накладные расходы, поэтому рекомендуется максимально использовать ее в крупных проектах.
Многопроизводительный параллельный код сжатия 🛵
Обычно в среде разработки время построения кода относительно быстрое, а процесс добавления сжатого кода при создании кода для публикации в Интернете требует большого объема вычислений и большого количества времени.
webpack
предоставляется по умолчаниюUglifyJS
плагин для сжатияJS
код, но он использует однопоточный код сжатия, что означает несколькоjs
Файл нужно сжать, его нужно сжать файл за файлом. Таким образом, очень медленно упаковывать сжатый код в формальную среду (из-за сжатияJS
Код нужно сначала разобратьObject
абстрактно представленныйAST
Синтаксическое дерево, а затем применять различные правила для анализа и обработкиAST
, в результате чего процесс занимает очень много времени).
Поэтому нам необходимо оптимизировать шаг сжатия кода, обычно это многопроцессорное параллельное сжатие.
В настоящее время существует три основных схемы сжатия:
- parallel-uglify-plugin
- uglifyjs-webpack-plugin
- terser-webpack-plugin
parallel-uglify-plugin
НадHappyPack
Идея состоит в том, чтобы использовать несколько дочерних процессов для анализа и компиляцииJS
,CSS
и т. д., так что несколько подзадач могут обрабатываться параллельно.После выполнения нескольких подзадач результаты отправляются в основной процесс.С этой идеей,ParallelUglifyPlugin
Плагин создан.
когдаwebpack
иметь более одногоJS
Когда файл необходимо вывести и сжать, он изначально использовалсяUglifyJS
сжимать и выводить один за другим, иParallelUglifyPlugin
Плагин откроет несколько подпроцессов и разделит работу по сжатию нескольких файлов на несколько подпроцессов для завершения, но каждый подпроцесс по-прежнему проходитUglifyJS
для сжатия кода. Параллельное сжатие может значительно повысить эффективность.
Установить
yarn add -D webpack-parallel-uglify-plugin
Пример
import ParallelUglifyPlugin from 'webpack-parallel-uglify-plugin';
module.exports = {
plugins: [
new ParallelUglifyPlugin({
// Optional regex, or array of regex to match file against. Only matching files get minified.
// Defaults to /.js$/, any file ending in .js.
test,
include, // Optional regex, or array of regex to include in minification. Only matching files get minified.
exclude, // Optional regex, or array of regex to exclude from minification. Matching files are not minified.
cacheDir, // Optional absolute path to use as a cache. If not provided, caching will not be used.
workerCount, // Optional int. Number of workers to run uglify. Defaults to num of cpus - 1 or asset count (whichever is smaller)
sourceMap, // Optional Boolean. This slows down the compilation. Defaults to false.
uglifyJS: {
// These pass straight through to uglify-js@3.
// Cannot be used with uglifyES.
// Defaults to {} if not neither uglifyJS or uglifyES are provided.
// You should use this option if you need to ensure es5 support. uglify-js will produce an error message
// if it comes across any es6 code that it can't parse.
},
uglifyES: {
// These pass straight through to uglify-es.
// Cannot be used with uglifyJS.
// uglify-es is a version of uglify that understands newer es6 syntax. You should use this option if the
// files that you're minifying do not need to run in older browsers/versions of node.
}
}),
],
};
❝❞
webpack-parallel-uglify-plugin
Больше не поддерживается, не рекомендуется здесь
uglifyjs-webpack-plugin
Установить
yarn add -D uglifyjs-webpack-plugin
Пример
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
plugins: [
new UglifyJsPlugin({
uglifyOptions: {
warnings: false,
parse: {},
compress: {},
ie8: false
},
parallel: true
})
]
};
По сути, это то же самое, что и вышеparallel-uglify-plugin
Точно так же вы также можете установитьparallel: true
Включить многопроцессорное сжатие.
terser-webpack-plugin
Я не знаю, нашли ли вы:webpack4
уже поддерживается по умолчаниюES6
Синтаксическое сжатие.
И это неотделимоterser-webpack-plugin
.
Установить
yarn add -D terser-webpack-plugin
Пример
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: 4,
}),
],
},
};
Предварительно скомпилированные модули ресурсов 🚀
Что такое предварительно скомпилированный ресурсный модуль?
В использованииwebpack
При упаковке для зависимых сторонних библиотек, таких какvue
,vuex
Для этих немодифицированных зависимостей мы можем упаковать их отдельно от кода, который мы написали сами.Преимущество этого в том, что каждый раз, когда я меняю файлы моего локального кода,webpack
Мне нужно только запаковать код файла самого моего проекта без компиляции сторонних библиотек.
Тогда сторонняя библиотека упаковывается только один раз, когда она упаковывается в первый раз, и пока мы не обновим сторонний пакет в будущем, тогдаwebpack
Эти библиотеки не будут упакованы, что может быстро повысить скорость упаковки. На самом деле, это预编译资源模块
.
webpack
, мы можем объединитьDllPlugin
а такжеDllReferencePlugin
плагин для реализации.
DllPlugin
что это такое?
Он отделяет код сторонних библиотек, и каждый раз, когда файл изменяется, он упаковывает только собственный код проекта. Так упаковка будет быстрее.
DLLPlugin
Плагин находится в дополнительном автономномwebpack
В настройках создайте толькоdll
изbundle
, то есть в корневом каталоге проекта, в дополнение кwebpack.config.js
, также создаст новыйwebpack.dll.js
документ.
webpack.dll.js
Роль состоит в том, чтобы упаковать все зависимости сторонних библиотек в одинbundle
изdll
В файле файл с именемmanifest.json
документ. Долженmanifest.json
используется, чтобы сделатьDllReferencePlugin
Сопоставлены со связанными зависимостями.
DllReferencePlugin
Что это такое?
Этот плагин находится вwebpack.config.js
используется в плагине, роль плагина заключается вwebpack.dll.js
упаковано вdll
Файл ссылается на необходимые предварительно скомпилированные зависимости.
Что это значит? то естьwebpack.dll.js
Например, после упаковки он сгенерируетvendor.dll.js
документы иvendor-manifest.json
документ,vendor.dll.js
Файл содержит все файлы сторонних библиотек,vendor-manifest.json
Файл будет содержать индекс всего кода библиотеки при использованииwebpack.config.js
упаковка файловDllReferencePlugin
При использовании плагинаDllReferencePlugin
плагин читатьvendor-manifest.json
файл, чтобы узнать, существует ли сторонняя библиотека.
vendor-manifest.json
Файл — это просто сопоставление сторонней библиотеки.
Как это использовать в проекте?
Столько всего было сказано выше, в основном для удобства всех预编译资源模块
а такжеDllPlugin
а также,DllReferencePlugin
Понимание функции плагина
Сначала взгляните на законченную структуру каталогов проекта:
В основном в двух конфигурациях, а именноwebpack.dll.js
а такжеwebpack.config.js
(соответствует здесь яwebpack.base.js
)
webpack.dll.js
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'production',
entry: {
vendors: ['lodash', 'jquery'],
react: ['react', 'react-dom']
},
output: {
filename: '[name].dll.js',
path: path.resolve(__dirname, './dll'),
library: '[name]'
},
plugins: [
new webpack.DllPlugin({
name: '[name]',
path: path.resolve(__dirname, './dll/[name].manifest.json')
})
]
}
Здесь я разобрал две части:vendors
(хранитсяlodash
,jquery
и т.д.) иreact
(Хранит связанные с реакцией библиотеки,react
,react-dom
Ждать)
webpack.config.js
(соответствует мне здесьwebpack.base.js
)
const path = require("path");
const fs = require('fs');
// ...
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
const webpack = require('webpack');
const plugins = [
// ...
];
const files = fs.readdirSync(path.resolve(__dirname, './dll'));
files.forEach(file => {
if(/.*\.dll.js/.test(file)) {
plugins.push(new AddAssetHtmlWebpackPlugin({
filepath: path.resolve(__dirname, './dll', file)
}))
}
if(/.*\.manifest.json/.test(file)) {
plugins.push(new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, './dll', file)
}))
}
})
module.exports = {
entry: {
main: "./src/index.js"
},
module: {
rules: []
},
plugins,
output: {
// publicPath: "./",
path: path.resolve(__dirname, "dist")
}
}
Здесь для демонстрации опущено много кода, полный код проектаэто здесь
Поскольку выше я разделил стороннюю библиотеку, соответствующее поколение тоже будет состоять из нескольких файлов.Здесь я читаю файл и делаю слой обхода.
Наконец вpackage.json
Просто добавьте к нему скрипт:
"scripts": {
"build:dll": "webpack --config ./webpack.dll.js",
},
бегатьyarn build:dll
Будет создана схема структуры проекта, размещенная в начале этого раздела~
Используйте кэш для увеличения второй скорости строительства
Вообще говоря, для статических ресурсов мы все надеемся, что браузер может кешировать, чтобы кешированные ресурсы можно было использовать сразу после входа на страницу, а скорость открытия страницы была значительно ускорена, что не только улучшает пользовательский опыт, но и экономит широкополосные ресурсы.
Конечно, есть много способов кэшировать браузеры, но вот краткое обсуждение.webpack
Как использовать кеш для повышения скорости вторичной сборки.
существуетwebpack
Обычно существуют следующие идеи использования кеша в Китае:
-
babel-loader
включить кеш - использовать
cache-loader
- использовать
hard-source-webpack-plugin
babel-loader
babel-loader
Во время выполнения могут быть созданы некоторые общие файлы, которые повторяются во время работы, что приводит к избыточному размеру кода и снижению эффективности компиляции.
можно добавитьcacheDirectory
Параметр для включения кэширования:
{
test: /\.js$/,
exclude: /node_modules/,
use: [{
loader: "babel-loader",
options: {
cacheDirectory: true
}
}],
},
cache-loader
В некоторых накладных расходахloader
добавить это передloader
, чтобы кэшировать результаты на диск.
Установить
yarn add -D cache-loader
использовать
cache-loader
Конфигурация очень простая, поставь в др.loader
до. ИсправлятьWebpack
Конфигурация выглядит следующим образом:
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.ext$/,
use: [
'cache-loader',
...loaders
],
include: path.resolve('src')
}
]
}
}
❝Обратите внимание, что сохранение и чтение этих файлов кеша потребует некоторого времени, поэтому используйте только ресурсоемкий
loader
loader
hard-source-webpack-plugin
HardSourceWebpackPlugin
node_modules/.cache/hard-source
hard-source-webpack-plugin
После первого раза время сборки почти не меняется, но со второго раза время сборки может сократиться примерно80%
о.
Установить
yarn add -D hard-source-webpack-plugin
использовать
// webpack.config.js
var HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
module.exports = {
entry: // ...
output: // ...
plugins: [
new HardSourceWebpackPlugin()
]
}
❝❞
webpack5
встроенныйhard-source-webpack-plugin
.
Сузьте цели сборки/уменьшите поиск файлов 🍋
Иногда мы используем много модулей в нашем проекте, но некоторые модули не нужно парсить. На этом этапе мы можем соответствующим образом оптимизировать сборку, сузив цель сборки или уменьшив диапазон поиска файлов.
Минимизировать цель сборки
в основномexclude
а такжеinclude
использование:
- исключить: модули, которые не нужно разрешать
- include: модули для разбора
// webpack.config.js
const path = require('path');
module.exports = {
...
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
// include: path.resolve('src'),
use: ['babel-loader']
}
]
}
здесьbabel-loader
исключитnode_modules
соответствующий следующемуjs
синтаксический анализ для повышения скорости сборки.
Уменьшить область поиска файлов
Это в основномresolve
Связанная конфигурация, используемая для установки способа анализа модуля. пройти черезresolve
конфиг, который может помочьWebpack
Быстро найти зависимости и заменить соответствующие зависимости.
-
resolve.modules
:Рассказыватьwebpack
Модуль синтаксического анализа должен искать каталог -
resolve.mainFields
: когда изnpm
При импорте модуля в пакете (например,import * as React from 'react'
), эта опция будет определять, когдаpackage.json
Какое поле используется в модуле импорта. согласно сwebpack
указано в конфигурацииtarget
отличается, значение по умолчанию будет другим -
resolve.mainFiles
: каталог для разбора имени файла, который вы хотите использовать по умолчанию.index
-
resolve.extensions
: расширение файла
// webpack.config.js
const path = require('path');
module.exports = {
...
resolve: {
alias: {
react: path.resolve(__dirname, './node_modules/react/umd/react.production.min.js')
}, //直接指定react搜索模块,不设置默认会一层层的搜寻
modules: [path.resolve(__dirname, 'node_modules')], //限定模块路径
extensions: ['.js'], //限定文件扩展名
mainFields: ['main'] //限定模块入口文件名
Сервис динамического полифилла 🦑
представлять动态Polyfill
Прежде давайте посмотрим, чтоbabel-polyfill
.
Что такое babel-полифилл?
babel
Отвечает только за преобразование синтаксиса, например преобразованиеES6
Преобразование синтаксисаES5
. Но если некоторые объекты и методы не поддерживаются самим браузером, например:
- глобальный объект:
Promise
,WeakMap
Ждать. - Глобальная статическая функция:
Array.from
,Object.assign
Ждать. - Методы экземпляра: например.
Array.prototype.includes
Ждать.
В этот момент необходимо представитьbabel-polyfill
Смоделировать и реализовать эти объекты и методы.
Это также обычно называют垫片
.
как использоватьbabel-polyfill
?
Он также очень прост в использовании, вwebpack.config.js
Файл можно настроить следующим образом:
module.exports = {
entry: ["@babel/polyfill", "./app/js"],
};
зачем использовать动态Polyfill
?
babel-polyfill
Потому что он импортируется сразуpolyfill
, поэтому очень удобен в использовании, но в то же время приносит и большую проблему: файл очень большой, поэтому последующие решения оптимизированы под эту проблему.
Посмотрите на упаковку послеbabel-polyfill
Доля:На его долю приходится 29,6%, что многовато!
По вышеуказанным причинам,动态Polyfill
Служба родилась.
Узнай по картинкеPolyfill Service
Принцип:
Каждый раз, когда вы открываете страницу, браузер отправляетPolyfill Service
послать запрос,Polyfill Service
ИдентифицироватьUser Agent
, отправить разныеPolyfill
, для загрузки по запросуPolyfill
Эффект.
как использовать动态Polyfill
Служить?
Можно использовать официальный адрес службы:
//访问url,根据User Agent 直接返回浏览器所需的 polyfills
https://polyfill.io/v3/polyfill.min.js
Scope Hoisting
🦁
чтоScope Hoisting
?
Scope hoisting
Дословный перевод — «продвижение масштаба». знакомыйJavaScript
Каждый должен знать «подъем функций» и «подъем переменных»,JavaScript
поднимет объявления функций и переменных в верхнюю часть текущей области. "Подъем объема" тоже похож на это,webpack
представитjs
Файл "поднят на" те, что вверху его введения.
Scope Hoisting
может позволитьWebpack
Упакованные файлы кода меньше по размеру и работают быстрее.
включитьScope Hoisting
быть вWebpack
используется вScope Hoisting
очень просто, потому что этоWebpack
Для встроенных функций необходимо настроить только один плагин, соответствующий код выглядит следующим образом:
// webpack.config.js
const webpack = require('webpack')
module.exports = mode => {
if (mode === 'production') {
return {}
}
return {
devtool: 'source-map',
plugins: [new webpack.optimize.ModuleConcatenationPlugin()],
}
}
включитьScope Hoisting
сравнение после
Давайте сначала посмотрим, нет лиScope Hoisting
ДоWebpack
способ упаковки.
Если сейчас два файла
-
constant.js
:
export default 'Hello,Jack-cool';
- входной файл
main.js
:
import str from './constant.js';
console.log(str);
Для приведенного выше исходного кодаWebpack
Упакованная часть кода выглядит следующим образом:
[
(function (module, __webpack_exports__, __webpack_require__) {
var __WEBPACK_IMPORTED_MODULE_0__constant_js__ = __webpack_require__(1);
console.log(__WEBPACK_IMPORTED_MODULE_0__constant_js__["a"]);
}),
(function (module, __webpack_exports__, __webpack_require__) {
__webpack_exports__["a"] = ('Hello,Jack-cool');
})
]
при открытииScope Hoisting
После этого часть кода, выводимого из того же исходного кода, выглядит следующим образом:
[
(function (module, __webpack_exports__, __webpack_require__) {
var constant = ('Hello,Jack-cool');
console.log(constant);
})
]
Видно, что открытиеScope Hoisting
После этого объявление функции изменилось с двух на одно,constant.js
Содержимое, определенное в, вводится непосредственно вmain.js
в соответствующем модуле. Преимущества этого:
- Размер кода меньше, потому что оператор объявления функции будет генерировать много кода;
- Накладные расходы на память также уменьшаются, поскольку код выполняется с меньшим объемом создаваемой функции.
Scope Hoisting
Принцип реализации на самом деле очень прост: анализировать зависимости между модулями и максимально объединять разбросанные модули в одну функцию, но предпосылка заключается в том, что нельзя вызвать избыточность кода. Таким образом, только те модули, на которые есть ссылка один раз, могут быть объединены.
❝из-за
❞Scope Hoisting
Зависимости между модулями необходимо анализировать, поэтому исходный код должен использоватьES6
Модульная инструкция, иначе не получится.
Ссылаться на
Geek Time [Играть с помощью веб-пакета]
❤️ Люблю тройное комбо
1. Если вы считаете, что эта статья неплохая, пожалуйста, помогитеподобноДавай, пусть больше людей увидят это~
2. Подпишитесь на официальный аккаунтпередний лес, регулярно снабжаем вас свежими и галантереями и хорошими товарами.
3. На спецучастках носите маску и пользуйтесь средствами индивидуальной защиты.
4. Добавьте WeChatfs1263215592, пригласите вас в группу технического обмена, чтобы учиться вместе 🍻
В этой статье используетсяmdniceнабор текста