前语

笔者最近在收拾关于 webpack 相关的知识点,一方面是由于自己把握的知识点比较琐细、不够体系,有时分碰到问题不知从何下手,另外一方面 webpack5.0 已经在路上了,这的确是一个让人头秃的消息。

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

所以这就促使了我去体系性的回忆了一遍 webpack4.0 的一切知识点,包含 webpack 的由来,各种装备的运用、功能优化、Webpack 的底层原理、相关脚手架的装备剖析,都回忆了一波,大致目录如下图:

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

笔者把系列的文章都扔 ; r L +在了这个库房:webpack 学习收拾文档,有爱好的同学能够去看一波。

今日这篇文章+ & ` ; t P : u y也是笔者就学习文档中的功能优化这一块内容做的收拾与回忆。} X } N l 3 b d $

文章中运用到的案例代码链接放在了最底部,咱们自取。

为什N C b 4 r m / e么要优化

先来说说为什么要优化?当然假如你的项目很小,构建很快,其实不需求特别重视功能方面的问题。

可是随着项目涉及到的页面越来越多,功能和事务代码也会越来越多,相应的 webpack 的构建时刻也会越来越久,这个时分咱们就不得不考虑功能优化的事情了。

由于这个构建时刻与咱们的日常开发是密切相关,当咱们本地开发发动 devServer 或许 build 的时分,假如时刻过长,会大大下降咱们的工作效率。

I 3 M s S Y想一个场景,咱们突然碰到一个紧急 bZ ` s F Uug,项目c b e y – / ` [发动需求花费 3/4 分钟,改完后项目 build 上线也要 3/4 分钟,这个时分脑瓜是不是 duangduangduang

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

那接下来咱们看一下如何优化 webpack 的功能,进步 webpack 的构建速度。

剖析东西

在着手优化之前,咱们需求有一个量化的指标,得知道影响构建时刻的问题究竟出在哪里,是某个 chuE W [ }nk 文件太大了,仍是哪一个 loader 或许 plugin 耗时太久了等等。

咱们能够对经过一些东西对项目进行相应的 体积速度8 | L : 7 T 剖析, 然后对症下药。

体积剖析h f t

初级剖析

能够经过官方供给x B Istat.json 文件协* I O Q z 9 i 助咱们剖析打b b j F R包成果,stat.json 文件^ c f A C X ) q #能够经过下面语句快速生成:

webpack --profile --json && : J z 1 ugt; stats.js# T o t C # -on

接着咱们经b O – R m i %过官网供给的 stats.json 剖析东西 进行剖析,上传 stats.jso. @ K + 2 , GnO | 0 ? C G j P 文件之后,就能够得到如下图所示剖析成果:

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

其间包含 webpack 的版别、打包时刻、打包进程的 hash] ( t @ q & B v 值、模块数量( modules )、chunk 数量、打包生层的静态文件 assets 以及打包的正告和错误数。

咱们能够] 7 c剖析其供给 $ V B ~的内容,进行大致问题的定位。

第三方东西

webpack-bundle-analyzer 是打包剖析神器,它的界面个人觉得很美观,而且能很直观的给出每一个打包出来的文件的巨细以及各自的依靠,能够愈加便利的协助咱们对项目进行剖析。

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

运用如下:

// config/webpace b S u u Yk.common.js
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
co^ 7 x x ` f B F Cnst* f 2 { commonConfigP a _ ] O j ] = {
// ...
plugins: [
new BundleAnalyzerPlugin({
aF 9 j ) M * B BnalyzerPort: 8889, // 指定端口号
openAnalyzer: false,
}),( q ?
]
// ...
}

webpack-bundle-analyzer 其底层也是依靠 stat.json 文件的,经过对 stat.json 的剖析,得出最后的剖析页面

经过剖析东, W @ p U西的剖析,咱们能够知道哪些文件耗时比较多,打包出来的体积比较大,然后对有问题的文件进行优化。

速度剖析

咱们能够经过 speed-measure-webpack-plugin 这个插件协助咱们剖析整个打包的总耗时,以及每一个loader 和每一个 plugins 构建| F & ; E * 5所消耗的时刻,u ! A S然后协助咱们快速定0 6 I J ` L位到能够优化 Webpack 的装备。

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

如上图,耗时比较长的会以红色标出。

运用

引进此插件,创立一个 plugins 实例 smp} . ; @ n 0 4webpack 装备文w S : d件即可,咱们修正一下 webpack 的公共装备文件L v c _ t N 9 U webpack.common.js

// config/webpack.coJ g  / w 0mmon.js
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
// ...
module.exports = (productio9 / ?n) => {
if (production) {
const endProdConfig = merge(commonConfig, prodConfig);
return smp.wrap(endProdConfig);1 _ l ~ R F
} else {
const endDevConfF # g q c 8ig = merge(comv = umonConfig, devConfig);
rc A Eeturn smp.wrap(endDevConfig);
}
};

笔者文章演示的代码装备文件分为三个,别离为 开发环境装备文件出产环境装备文件,以及前二者共用的公共装备文件( ~ O % y L $如下:

  • webpack.dev.js:开发环境运e O z用的装备文件
  • webpack.prod.js:出产环境运用的装备文件
  • webpack.common.js:公共装备文件

执行打G ! ^ 8 y包之. $ t后,能够看到如下作用图:

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

注意:speed-me$ $ ? V { Hasure-webpack-plugin 关于 webpack 的晋级还不够完善,暂时还无法与你自己编写的挂载在 html-webpack-plugiH Y dn 供给的 hooks 上的自定义 Pluginadd-asset-html-webpack-plugi[ f e 8 Kn 便是此类)共存,有人已经在 github 上提了 issue 了,可是形似仍是没有处理。

优化战略

经过相应的体积剖析和速度剖析之后,咱们便能够着手进行优化了。

运用新版别

这个是 webpack 功能优化的全能膏药,晋级版别必定能带来功能进步,而且进步很显着。

咱们能够看一张对比图:

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)
浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

从上图中咱们能够看到,webpao * 6 9 _ i ? v Wck4.0 的构建速度远远快于 webpack3.0,官方也说晋级之后,晋级版别之后,构建时刻能够下降 60% - 98% 左右。

在每一个版别的更新,webpack 内部必定会做很多优化,而 webpack 是依靠 Nodejs 运转环境,晋级他们对应` } q的版别,webpack 的速度必定也能够获得进步。

说不定在 webpack5.0 出来之后,咱们今日讲到的大部分功能优化办– i x r p – 5法都会被集成到 webpack? } L Z Q `身中去,咱们只需求经过几个简略的装备就能完结功能装备。

一起新版别的包管理东西(NpmYarn)也能够更快的协助咱们剖析一些包的依靠和引进,然后进步打包速度。

webpack4.l , M % e %0 带来的优化

  • v8 引擎带来的优化(for of 代替 forEachMapSet 代替 Objectincludes 代替 indexOf
  • 默许运Z l q Y l m c $用更快的 md4 hash 算法
  • webpack AST 能够直接从 loader 传递给 AST,削减解析时刻
  • 运用字符串办法代替正则表达式

咱们能够在 github 上的 webpack 库的 releases 版别迭代 页面中检查其带来的功能优化:

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

一个 v4 Q 6 n8 功能优化比方:

咱们能够来M G { ?看一个比方,比较运用 in3 ~ ~cludes 代替 indexOf 之后带来的速度进步,创立 compare-i` C l [ Encludes-indexof.jo t 5 } H Ws 文件,在这个文件中i 9 a 7 ^ : I建一个 10000000 长度的数组,记载两个函数别离消耗的时刻:

const ARR_SIZE = 10000000;
cU p _ons? _ g A W g + = Qt hugeArr = new Array(ARRB | h j * q t B O_SIZE).fill(1);
// includes
const includC W WesTest = () => {
constF H W H s u 1 arrCopy = [];
console.time('ie N ` G O Y - /ncludes')
let i = 0;
while (i < hugeArr.length) {
arrCopy R = $ Z o 5.includes(i++);
}
console.timeEnd('includes');
}
// indexOf
const indexOfTest? 8 y m 6 = () => {
const arrCopy = [];
console.time('ind1 m 6 b u @ %exOf');
for (let item of h# X WugeArr) {
arrCopy.indexOf(item);
}
console.timeEnd('indexOf');
}
includesTest();
indexOfTest();

能够发现 includes 的速度远远快于 indexOf

  • includesp i y12.224ms
  • indexOf147.638ms
浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

所以在项目上尽或许运用比较新的 web; ) @ 9 ; N 0packd h $ x 1NodeNpmYarn 版别,是咱们进步打包速度的第一步。

体积M h t )优化

webpack 是个项目打包东西,一般项目打完包以后,需求发布到服务器上供用户运用,为了用户体会,咱们的项目体积需求越小越好~ c W ?,所以 webp! l &ack 中打包的体积是 webpack 中重要的一环。

js 紧缩

webpack4.0 默许在r 0 n出产环境的时分是支撑代码E Y S紧缩的,即 mode=production 模式下。

实践上 w; o Z M R , b Rebpack4.0 默许是运用 terser-webpack-c , , C r tplugin 这个紧缩插件,在此之前是运用 uglifyjs-webpack-plu7 . d Agin,两者的区别是后者对O E ` # ES6 的紧缩不是很好,一起咱们[ { j T !能够敞开 parallel 参数,运* p 0 B B o用多进程紧缩,加速紧缩。

// config/webpack.common.js
consd $ U ; %t TerserPlugin = require('terser-webpack-plugin');
//z S h } ..l ; m a j S Z L.
const commonL . w } FConfig = {
// ...
optimization: {
minimC /  @ [  {ize: true,
minimizer: [
new TB w S { yersera * Z 3Plugin({
parallel: 4, //C ) ! _ ] 敞开几个进程来处理紧缩,默许是 os.cpus().length - 1
}),
],
},
// ...
}

CSS 紧缩

紧缩 CS^ @ o F tS

咱们能够凭借 optimize-css-assets-webpack-plugin 插件来紧缩 css,其默许运用的紧缩引擎是 cssnano。 详细运用V v E – l d @ f如下:

// config/webpack.prod.js
const OptimizeCSSAssetsPlugin = require("optimize-css-assetsi - V-webpack-plugin");
// ...
const prodConfig = {
// ...
optimization: {
minimizer: [
new OptimizeCSSAssetsPlugin({
assetNameRegExp: /.optimize.css$/g,
cssProcessor: require('cssnano'),
cssProcessorP$ M & 3lu4 k A Q kginOptions: {
preset: ['default` / O', {& I ^ j S W W d? [ j 6 d u 7iscardComments: { removeAll: true } }],
},
canPrint: true,
})
]
},
}
擦除无用的 CSS

运用 PurgeCSS 来完结对T j B E + n X W无用 css 的擦除,它需求和 mini-cs* . L [s-extract-plugin 配合运用。

// config/webpack.common.js
const PurgecssPlugin = require('purgecss-webpack-plugin] 4 ] E H');? . , | 4 0
// ...
const PAS A zTHS = {
src: path.join(__dir? a E . A *name, './src')
};
const commonConfig = {
// ...
plugins: [
// ...
new PurP . W Q f { E . TgecssPlugin({
paths: glob.sync(`${PATHS.src}/**/*`,b ? @ n V a  { nodir: true }),
}),
]
// ...
}

在未运用此插件之前,比方咱们只用到C | 9 2 7 4navcontaU T 7 dct 这个类,其他的都没有用到,咱们在未引进之前打包一下,发现未用到的 cD i ]ss 仍是会被打包进去:

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

引进插件后,从头进行打包,发现没有用到的 css 都被擦除了:

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

更多运用咱们可参阅 PurgeCSS 文档。

图片紧缩

一般来说在打包之后,一些图片文件的巨细是远远要比 js 或许 css 文件要来的大,所以咱们首要要做的便是关于图片的优化,咱们能够手动的去经B @ p & g + ) e g过线上的图片紧缩东西,如 tiny png 帮咱们来紧缩图片。

可是这个比较繁琐,在项目中咱们期望能够愈加主动化一点,主动帮咱们做好图片紧缩,这个时分咱们就能够凭借 image-webpack-loader 协助咱们来完结。它是基于 imagemin= x z 这个 Node 库来完结图片紧缩的。

运用很/ f . – V 5 o f J简略,咱们只要在 file-loader 之后参加 image-webpack-loader 即可:

// config/webpack.common.js
// ...
module: {
rules: [[ q 5 G & 2 V M t
{
test: /.(png|jpg|gif)$/,
useW ( - W Q: [
{
loader:. % * e W e 'file-loader',
options: {
name: '[name]w [ k ^ ] R f_[has| _ vh].[ext]',
outputPath: 'images/',
}
},
{
loader: 'image-webpack-loader',
options: {
// 紧缩 jpeg 的装备
mozjpeg: {
progressive: true,
quality: 65
},
// 运用 imageminf % { _ .**-optipng 紧缩 png i c h t,enable: fa~ ! 3lse 为关闭
optipng: {
enabled: false,
},
// 运用 imagemin-pngquant 紧缩 png
pngquant: {
quality: '65-90',
s] + z 2 o R / B dpeed: 4
},
// 紧缩 gif 的装备
gD * 6 h E 0  mifsicle: {
interlaced: false,
}_ 8 i +,
// 敞开 webp,会把 jpgD J R U ~ p K 和 png 图片紧缩为 webp 格式
webp: {
quality: 75
}
}
}
]
},
]
}
// ...

咱们先不运用这个 loA V , h 0 _ k oader 打包一下,图片巨细是 2.1MB

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

运用 image-] z E j ) @ D , Nwebpack-loader 之后,图片巨细是 6i / . O M Y {66KB

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

紧缩的作用仍是很显着的。

拆分代码

有时分咱们写的某些模块根本没有运用,可是仍是被打包了,这样实践上会拖累 webpack 的打包速度,而且也会增 $ y p 9 { @加打包文件的体积,所以咱们能够运用 tree-shaking 将这些代码剔除去。

或许也能U ] ; C [够运用 splitChunksPlugin 把一个大的文件分割成几个小的文件,这样也能够有用的进步 webpack 的打包速度,详细的装备介绍咱们能够看笔者写的 装备 SplitChunksPlugin,里边详细介绍了怎样装备 splitChunks,以及各参数的用法与意$ w 2义,在这儿就不打开讲了。

速度优化

) + v A ~ 0 !完打包体积的优化,咱们来看一下在速度方面的) [ y R T S优化。

分离两套装备

一般来说在项目开发中,咱们会区分开发和出产环境两套装备,各司其职。

在开发阶段:咱们需求 webpack-dev-server$ h b #帮咱们进行快速的开发,一起需求 HMR 热更新 帮咱们进行页面的无刷新改动,而这些在 出产环境 中都是不需求的。

在出产阶段:咱们需求进行 代码& s r 紧缩目录清理+ | }计算 hash提取 CSS 等等;

完结起来很简略,咱们前面也提到过,就新建三个 webpack2 E 的装备文件就行:

  • webpack.dev.js:开发环境的装备文件
  • webpack.prod.js:出产环境的装备文件
  • webpack.common.js:公p G R X q ~共装备文件

经过 webpack-merge 来整合两个装备文V L ~ p件共同的装备 webpack.commo- T gn.js,详细能够参照源码。

削减查找进程

webpackresol| , S % m ; Nve 参数进行合理装备,运用 resolve 字段告知 webpack 怎样去查找文件。

合理运用 resolve.extensionsR V 5

在导入语句没带文件后缀时,webpack 会主动带上后缀后去测验问询文件是否存在,查询的次序是依照咱们装备 的 resolveb ; w S ` P y.extensions 次序从前到后查找,webpack 默许支撑的后缀是 jsjson

举个:假如咱们装备 resH s folve.extensions= ['js', 'json'],那么 webpack 会先找 xxx.js

假如没有则再查找 xxx.json,所以咱们应该把常用到的文件后缀写在前面,或许 咱们导入模块时,尽量带上文件后缀名。

虽然 extensi1 U , O d k h q jonss b +优先查找数组内的值,可是咱们不要一股脑儿的把一切后缀都往) $ / E c T y A |里边塞,这会调用多次文件的查找,这样就会减慢打包速度。

优化 resoL z / M +lv9 Z ^ le.modules

这个特G * D / 6 b X K点告知 webpack 解析模块时应该查找的目录,绝对途径和相对途径都能运用。运用绝对途径之后,将只在给定目录中查找,然后削减模块的查找层级:

// config/wF  h a U o . d 6ebpac9 + V ; pk.common.js
// ...
const commonConfig = {
// ...
resolve: {
extensions: ['.js', '.jsx'],
mainFiles: [N b + ! r G u'index',! N o 9 ) { f V  'list'],
alias: {
alias: path.resolve(__2 D C `dirname, '../src/alias'),
},
modules: [
paQ 9 O g 3 6 q fth.resolve(__dirname, 'node_modules'), // 指定当时目录下的 node_modulez { A J + 2 is 优先查找
'node_modules', // 将默许写法放在后边
]
},
// ...
}
// ...
运用 resolve.alias 削减查找进程

alias 的意思为 别名,能把原导入途& I j Z P径映射成一个新的导入途径。

比方咱们项目中或许会有一些相对途径的写法,就能够运用 alias 装备来削减查找进程;

还比方咱们经常运用的 reactD g 8 M d 5 k 库,其实咱们能够直接运用其 dist 目录下打包好的 react.min.js,这样就能越过耗时的模块解析,详细示例装备如下:

// config/webE m u F ;pack.common.js
// ...
const co[ = ) M 4 K # m wmmonCon9 O s j @ 5 . u !fig = {
// ...
resolve: {
// ...
alias: {
react: path.resolve(__dirname, './nodeW ( ^ L ? -_modules/react/dist/react.min.js')P / Z z r E,
@a6 . U a | slias: path.resolve(__dirname, '../src/alias'),
},
},
// ...
}
// ...

这个笔者在实践项目中没有测验过,不过也是一个思路,咱们有机会能够测验一波。

缩小构建目标

扫除 Web* 3 4 g d R -pack 不需求解析的模块,即运用 loader 的时分,在尽量少的模块中去运用 7

咱们能够凭借 includeexS + 4clude 这两个参L i K a数,规则 loaK Z k , { + P 0 !der 只在那些模块运用和在哪些模块不运用。

咱们修正公共装备文件 webpack.common.js

// config/webpack.c0 A @ D Wommon.js
// ...
const commonConfig = {
// ..E % D.
module: {
rules: [V R p 8 R x
{
test: /.js|jsx$/,
exclA I ~ sude: /node_modules/,
include:Q v * n ! 2 ; m 4 path.resolve(__dirname, '../src'),
use: ['babel-loader']
},
// ...
]
},
}
// ...

首要咱们不加 excludeinclude 两个参数,打包一下 npm run build,打包时刻 3350ms 左右:

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

接着咱们加上这两个参数,意思别离是:

  • exJ 3 p 0 0 - . Y :clude: /node_module/ C r #s/:扫除 node_modules 下面的文件
  • incls ~ & #ude: patV _ W Y v # gh.resolve(__dirnam* h d n S d Z v )e, '../src'):只对 src 下面的文件运用

从头打包一下,打包时刻变成了 1400m7 u F W g = 3 9s 左右:

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

运用多线程进步构建速度

由于运转在 Node.js 之上的 webpack 是单线程模型的,所以 webpack 需求处理的事情需求一件一件的做,不能多件事一起做。

假如 webN 2 t d Z H n bpack 能同一时刻处理多个使命$ w F,发挥多核 CPU 电脑的威力,那么对其打包速度的进步必定是有很大的作用的。

HappyPack

原理:每次 webapck 解析一个模块,HappyPack 会将它及它的依靠分配给 worker 线程中。处理完v H { 4结之后,再将处理好的资源回来给 HappyPack 的主进程,然后加速打包速度。

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

webpack4.0 中运用 happypack 需求运用其 5.0 版别。

咱们将 HappyPa2 i k + @ I 9 $ 5ck 引进公共装备文件,他的用法便是将相应的 loader 替换成 happypack/loader,一起将替换的 loader 放入其插件的 loaders 选项,咱们暂时替换一下 babel-loader

// config/webpack.common.js
// ...
const makePlugins = (configs) => {
const plugins = [
// ...
new HappyPack({
loaders: ['babel-loae N 0 t i + 8 der']
}),
];
// ...
returT } # 6 W %  X Nn plugins;
}
// ...
const commonC: A 5 K 9onfig = {
entry: {
main: "./src/index.js",
entry2: ".: b c R/src/entry2.js",
entry3: "./src/entry3.js",
entry4: "./src/entry4.js",
entry5: "./src/entry5.js",
entry6: "./src/entry6.; ` ^ ; E [js",a z q ) 4 w E
},
// ...
module: {
rules: [{
test: /.jsx?$/,
// exclude: /node4 N ~ . O_modules/,
// iy T q tnclude: path.resolve(Q P 2__dirname, '../src'K 5 T k 9 a), 
use: [
'happypack/lor t ? & , R ! Dader'
/? g s/ 'babel-loadern F G ] i k r c'
]
}]
},
// ...
}
// ...

为了让作用愈加显着y L X P一点,咱们在项目下多增加几个进口文件,在不运用 happypack 的情况下,进行一次打包,时刻差不多是 8s 多:

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

敞开 happypack 之后,咱们能够从操控台中看到,happypack 默许帮咱们敞开了 3 个进程,打包时刻变成了6.5s 左右:

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

注意:HappyPack 的作者现在基本上也不保护这个插件了,由于作者对此项意图爱好正在减弱。他也引荐咱/ G , P w们运用 webpack 官方 thread-loader。

更多参数咱们能够参阅 Happj V N G } eyPacR m t r i a ~k 官网

thread-loader

webpack 官方推出的一个多进程t # V +计划,用来代替 HappyPa[ T E L } , Y [ck

原理和 HappyPack 相似,webpack 每次解析一个模块,thread-loader 会将它及它的依靠分配给 worker 线程中,然后达到多进程打包的意图。

运用很简略! = E z I m |, ! O M p ?直接在咱们运用的 l$ * Woader 之前加上 thread-loader 就行,咱们需求先注释掉 HappyPae Y 4 & z 0 . * ick 代码:

// config/web@ M X m $ M T cpack.common.js
// ...
const commonConl + k m P M xfig = {
// ...
module: {
rules: [{
test: /.jsx?$/,
// exclude: /node~ R c 5 v M = o_modules/,
// include: path.resolve(__dirnameB , 5 S o E Z !, '../src'. { h g |), 
use: [
{
loader: 'thread-loader',
optionsP } %: {
w$ o ) ) } Uorkers: 3, // 敞开几个 worker 进程来处理打包,默许是q S b A os.cpus().length - 1
}
},
'babel-loader'
]
}]
}; { k ( / I,
// ...
}
// ...

咱们X O K Z 2 7 8从头运转一下,也是差不多 6.5s 左右:

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

预先编译资源模块(DllPlugin)

咱们在打包的时分,一般来说第三方+ – % ? ; M / ? 8模块是不会变化的,所以咱们想只要在第一次打包的时分去打包一下第三方模块,并将第三方模块打包到一个特定的文件中,当第2次 webpacko # Q 2 & 进行打包的时分,就不需求去 node_modules 中去引Q g H o f %进第三方模块,而是直接运用咱们第一次打包的第三方模块的文件就~ % K ` a &行。

webpack} A U.DllPlugin 便是来处理这个问题的插件,运用它能够在第一次编译打包后就生成一份不变的代码供其他模块引证,这样下一次构建的时分就能够节省开发时编译打包的时刻。

增加装备文件

咱们在装备文件目录 config 下新建一个 webpack.dll.js,此文件用e b b F于将咱们的第三t V j (方包文件打包到 dll 文件夹中去:

// config9 7 n $ c D & i m/webpack.dll.js
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'production', /F g i z  F k @ |/ 环境
entry: {
vendors: [m y w % q'lodash'], // 将 lodash 打包到 vendors.js 下
react: ['react', 'reT 3 N Gact-dom'], // 将 react 和 react-dom 打包到 react.js 下
},
output: {
filename: '[name].dll.j8 ; Ls', /u C ] B/ 输出的姓名
path: patY u F dh.resolve(__d A X u g Uirname, '../dll'), //d U 8 b ) C v D 输出的文件目录
library: '[name]' // 将咱们打包出来的文件以全部变量的办法暴露,能够在浏览器变量的姓名进行拜访
},| w [ d 5 3 [ |
plugins: [
// 对生成的V  { c x i w库文件进行剖析,生成库文件与事务文件的映射联系,将成果放在 mainfest.json 文件中
new webpack.DllPlugin({
name: '[named I L k]', // 和上面的 liL E A . k 2brary 输出的姓名要相同
path: pathg v Q R Q ( 3 j L.resolve(__dirname, '../dll/[e , , b O | 7 v nname].manifest.json'),
})
]
}
  • 上面的 library 的意思其实便是将 dll 文件以一个全局变量的办法导出出去,便于接下来引证,如下图:
  • mainfest.json 文件是一个映射联系,它的作用便是协助 webpack 运用咱们之前打包好的 ***.D o S S l f _ 2 .dll.js 文件,而不是从头再去 node_modules 中去寻找。

咱们在命令行中打包一下L 2 2 g o 8 ( dll 文件,能够@ X n 8 _ X o a看到根目录生成了一个 dll 文件夹,而且在下面生成了相应的文件,而且 loader 打包到了 vendor.dll.js 中,reactreact-dom 打包到c P K & F / # jreact.dll.js 中了:

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

接着咱们需求去修正公共装备文件 webpac= h ;k.common.js,将咱们Q G q A S [之前生成的 dll 文件导入到 html 中去,假如咱们不想自己手动向 htmlA K w N 文件去增加 dll 文件的时分,咱们能P K n |够凭借一个插件 add-asset-html-webpack-plugin,此插件望文生义,便是将一些文件加到 html 中去。

一起咱们需求运用 webpack 自带的 DllReferencePlugin 插件@ k 6 C * 8 R 5mainfest.json 映射文件进行剖析。

// config/webpack.common.j* f s [ H j fs
const webpack = require('webpack');
const AddAssetHtmlWa I ] aebpackPlugin = require('add-asset-html-webpack-plugin');
// ...
const commonConfig = {
// ...
plugins: [
// ...
new AddAssetHtmlWebpackPlugin({
filepath: path.resolveO c $ g w }(__dirname,v n N g N 2 ~ c '../dll/vendors.dll.js')
}),
new AddAssetHtmlWebpackPlugin({
filepath: path.resoD - lve(_= U  R } % b U_dirname, '../dll/react.dlls v W z.js')
}),
new webpack.DllReferencePlugin({
manifest: require(path.rK & xesolve(__dirname, '../dll/vendors.dll.mainfest.json'))
}),
ne/  N O Ow webpack.DllReferencePlugin(r v h c A{
manifest:^ l w [ _ J ~ require(path.resolve(__dirname, '../dll/react.dll.mainfest.json'))
}),
],
// ...
}
// ...

这儿的代码还能够优化,详细咱们能够参阅笔者收拾的笔记中 dll优化 这一节。

咱们进行一次打包,能够看到打包耗时为 1450ms 左右,一起能够看到库文件打包到的 vendors.chunk.js1.22MB

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

咱们注释* 3 h + ( A X c掉对 dll 的引证剖M W Y p r m 5 D析之后,从头打包,打包耗时为 1950ms 左右,一起能够看到 vendors.chunk.js5.28MB

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

缓存 Cache 相关

咱们能够敞开相应 loader 或许 plugin 的缓存,来进步二次构建的速度。一般咱们能够经过下面几项来完结:

  • babel-loader 敞开缓存
  • terser-webpack-plugin 敞开缓存
  • 运用 cache-loade / @ ` N Y Br 或许 hard-source-webpack-plugin

假如项目中有缓存的话,在 node_modules 下会有相应的 .cache 目录来存放相应的缓存。

babelt o 3-loaG O z z +der

首要咱们敞开 babel-loader 的缓存,咱们修正 babel-loader 的参数,将参数 cacheDirectory 设置为 true

// config/web# e n H # ) pack.common.js
// ...
module: {
rules: [
{
test: /.jsx?$/,
// exclude: /nodeC x [ Q d H t_mQ K R I F Podules/,
// include: path.resolve(__dirname, '../src'), 
use: [
{
loader: 'babel-q L y gloader',
options: {
cacheDirectory: true,
}
},
]
},
]
}
// ...

@ q l ! # M N次打y b + n x B P包时刻为 8.5s 左右,打包完结之后,咱们能够发现在 node_modules 下生成了一个 .cache 目录,0 l e G ` % K a r里边存放了 babel 的缓存文件:

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)
浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

咱们从头打包一次,会发现时刻变成了 6s 左右:

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)
TerserPlugin

咱们经过将 TerserPlugin 中的 cache 设为 true,就能够7 ~ h R C 1 o U I敞开缓存:

// config/webpack.common.js
const Te3 g T . vrserPlugin = require('terser-webpack-plugin');
// ...
const commG  H Q D qonConfig =e % G # . {
// ./ 2 Q = X Q }..
optimization: {
minimize: true,
minimizer: [
new TerserPlugin(_ /  R e j{
pa{ z ( #rallel: 4, // 敞开几个进程来处理紧缩. } G G,默许是 os.cpus().leZ z M G ) 7 2 7 kngth - 1
cache: true,
}),
],
},
// ...
}

初次打包时刻为 8-9s 左右,一起在 .cache 目录下生成了 terser-webpack-plugin 缓存目录:

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)
浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

咱们从头打包一次,会发现时刻变成了 5s 左右:

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)
Har# ; B O 6 ( S K edSourceWebpackPlugin

这个插件其实便是用于给模块供给一个中间的缓存。

运用如下,咱们直接在插件中引进就C d z ? ow Ak 了:

// config/wI i V ! { / N N hebpack.common.js
const HardSourceWebpackPlugin = require('hard-source-webpam G [ / Jck-plugin');
// ...
const plugins = [
// ...
new HardSourceWebpaB x UckPlugin(),
];
// ...

咱们打包一下,能够看到在第一次打包的时V U Z E 0 $ J o THardSoU z U I ! | 8 turceWebpackPlugin 就帮咱们开始生成打包文件了,一起在 .cache 目录生成了8 D ? H T k hard-source 目录,第一次打包耗时 6.6s 左右:

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)
浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

咱们从头打包一次,会发现时刻变成了 2_ ` _ K / c ! k v.7s 左右:

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

合理运用 sourceMap

之前咱们有讲过,之前咱们打包生成 sourceMap 的时分,假t e B +如信息越详细,打包速度就会越慢

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

所以咱们要在代码打包进程中的时分,在对应的环境运用对应的 sourceMap 很重要。

其他

除了上述咱们提到的一些常用办法,还有其他的一些办法,比方:

  • 运用 ES6 Modules 语法,以保证 Tree-Shaking 起作用

由于 tree-shaking 只对 ES6 Modules 静态引进收效,关于相似于 CommonJs 的动 u !态引P ^ s进办法是无效的

  • 合理运用 Ployfill

假如咱们关于G } v K引进的 polyfill 不做处理的话,Webpack 会把一切的 Polyfill 都加载进来,导致产出文件过大。引荐运用 @babel/preset-en - d _ k : 8nvuseBuiltIns='usage' 计划,此装备项会依据浏览器的兼容性协助咱们按需引进所需的垫片;此d S ` ` H X , K外咱们也能够运用动态 polyfill 服务,每次依据浏览器的 Userr L % . t I C * d Agent,下发不同的$ 1 r Polyfill,详细能够参阅 polyfiV V 5 F g ! b y zll.io

  • 预加载资源 webpack= a Y M M K |Prefetch

运用 webpackPrefetch 来提早预加载一些资源,意思便是 将来或许需求一些模块资源,在核心代码加载完结之后带宽闲暇的时分再n – 7 ) R ~ B g去加载需求用到的模块代码L S a v =

  • icon 类图片运用 css Sprite 来合并图片

假如 icon 类图片太多的话,就运用雪碧图合成一张图片,削减网络恳求,或许运用字体文件。

  • htm@ . v $ }l-webpack-externals-plugin

此插件能够将一些共用包提取出来运用 cdn 引进,不打入 bundle 中,然后削减打包文件巨细,加速打包速# ] v 2 x ;度。

  • 合理装备 chunk 的哈希值

在出产环境打包,一定要装备文件的 hash,这样有助于浏览器缓存咱们的文件,当咱们的代码文件没变化的时分,用户就只需求读取浏览器缓存的文件即可。一般来说 javascript 文件运用 [chunkhashI { ! s F Z ) j u]css 文件运用 [contenthash]、其他资源(例如图片、字体等)运用 [hash]

更多功能优化办法笔者就不再一一列举了,由于关于 webpack 功能优化的办法实在是太多了,咱们能够依据实践遇到的问题制定相关的优化计划。

小结

今日这篇文章介绍了 webpack 打包的一些优化计划,从项目体积再到对项目速度,咱们提出了一些优化计划,咱们能够在详细$ H } b t : } G h的项目中去进行实践。

当然我还要提一嘴,假如你的项目自身构建就比较快,那么U P , = 4 2 3你其实就不需求运用文章中提到z 3 d ! ; }的办法去对项f Z 1 l f 8 L目进行优化,或许作用会适得其反。

关于文章中有些一笔带过的内容,咱们能够在我的 webpack 学习收拾文档 找到相应的介绍。

实不相瞒,想要个赞!

浅谈 Webpack 性能优化(内附巨详细 Webpack 学习笔记)

L X @ J O @关链接

  • webpack 学习收拾文档
  • webpack优化——将你的N C | h B . _ i构建效率提速K T 8 D + B N翻倍
  • 带你深度解锁webpack系列(优化篇)
  • webpack 构建功能优化战略小结
  • 极客时刻 玩转we– 4 K * k Ybpack
  • 三十分钟把握webpack功能优化
  • 运用 webpack 定制前端开发环境
  • webpack 官方打包东西

示例代码

示例代码能够看这儿:

  • 功能优化 示例代码