上一篇咱们讲到,webpack3.x 升级 4.x 后打包大小优化,今天讲一下 webpack 4.x
(webpack 4.43.0) 的打包速度优化,其实在升级了 webpack4
以后对于打包速度就已经有了很大的提高,可是查找时间(缩小范围)、loader
处理时间(多进程)、二次打包时间(缓存)仍有可优化的空间。css
在优化以前咱们须要清楚项目打包的性能状况,这里咱们使用 speed-measure-webpack-plugin 插件来进行分析html
webpack.base.jsvue
+const SpeedMeasurePlugin = require('speed-measure-webpack-plugin');
+const smp = new SpeedMeasurePlugin({
+ outputFormat: 'humanVerbose'
+});
const webpackConfig = merge(baseWebpackConfig, {
// ..
});
-module.exports = webpackConfig;
+module.exports = smp.wrap(webpackConfig);
复制代码
打包看下,本次耗时 62,361 ms
,列出了 Plugins
和 Loaders
具体耗时的细节:node
图比较长可是基本能看出,其中耗时较多的是 vue-loader
和 ts-loader
webpack
webpack
从入口文件开始,根据依赖关系查找模块,咱们要尽量少的处理模块,最多见的就是排除 exclude: /node_modules/
,exclude
和 include
同时使用时 exclude 优先级更高git
webpack.base.jsgithub
module.exports = {
module: {
rules: [
{
test: /\.vue$/,
loader: "vue-loader",
},
{
test: /\.js$/,
loader: "babel-loader",
// 确保 node_modules 中 Vue 单文件组件的 <script> 部分能被转译
exclude: (file) => /node_modules/.test(file) && !/\.vue\.js/.test(file),
},
{
test: /\.tsx?$/,
loader: "ts-loader",
exclude: /node_modules/,
options: {
// 禁用类型检查,能够经过插件的方式使用
transpileOnly: true,
experimentalWatchApi: true,
appendTsSuffixTo: [/\.vue$/],
},
},
],
},
};
复制代码
ts
类型检查,能够单独使用插件: ForkTsCheckerWebpackPluginweb
Each worker is a separate node.js process, which has an overhead of ~600ms. There is also an overhead of inter-process communication. 每一个
worker
都是一个单独的node.js
进程,其开销约为600
毫秒。进程间通讯也有开销。查看更多npm
webpack.base.js缓存
// ...
const isProduction = process.env.NODE_ENV === "production";
if (isProduction) {
const threadLoader = require("thread-loader");
// 预热 worker
threadLoader.warmup(
{
// pool options, like passed to loader options
// must match loader options to boot the correct pool
},
[
// modules to load
// can be any module
"babel-loader",
"ts-loader",
"vue-loader",
"sass-loader",
]
);
}
module.exports = {
// ...
module: {
rules: [
{
test: /\.vue$/,
use: isProduction ? ["thread-loader", "vue-loader"] : ["vue-loader"],
},
{
test: /\.js$/,
use: isProduction
? ["thread-loader", "babel-loader"]
: ["babel-loader"],
exclude: (file) => /node_modules/.test(file) && !/\.vue\.js/.test(file),
},
{
test: /\.tsx?$/,
loader: "ts-loader",
exclude: /node_modules/,
use: isProduction
? [
"thread-loader",
{
loader: "ts-loader",
options: {
happyPackMode: true,
transpileOnly: true,
experimentalWatchApi: true,
appendTsSuffixTo: [/\.vue$/],
},
},
]
: [
{
loader: "ts-loader",
options: {
transpileOnly: true,
experimentalWatchApi: true,
appendTsSuffixTo: [/\.vue$/],
},
},
],
},
{
test: /\.s?css$/,
use: isProduction
? [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "thread-loader",
options: {
workerParallelJobs: 2,
},
},
"sass-loader",
]
: ["vue-style-loader", "css-loader", "sass-loader"],
},
],
},
};
复制代码
ERROR in ./src/main.ts
Module build failed (from ./node_modules/thread-loader/dist/cjs.js):
Thread Loader (Worker 0)
Cannot read property 'errors' of undefined
at PoolWorker.fromErrorObj (/Users/yourProjectPath/node_modules/thread-loader/dist/WorkerPool.js:262:12)
at /Users/yourProjectPath/node_modules/thread-loader/dist/WorkerPool.js:204:29
at mapSeries (/Users/yourProjectPath/node_modules/neo-async/async.js:3625:14)
at PoolWorker.onWorkerMessage (/Users/yourProjectPath/node_modules/thread-loader/dist/WorkerPool.js:170:35)
at successfulTypeScriptInstance (/Users/yourProjectPath/node_modules/ts-loader/dist/instances.js:119:28)
at Object.getTypeScriptInstance (/Users/yourProjectPath/node_modules/ts-loader/dist/instances.js:34:12)
at Object.loader (/Users/yourProjectPath/node_modules/ts-loader/dist/index.js:17:41)
复制代码
ts-loader
设置 happyPackMode: true
,查看更多
看 webpack 文档有提到说 node-sass
搭配 thread-loader
使用的时候须要设置 workerParallelJobs: 2
,亲测发现如今不用这样设置了,速度会快一些
thread-loader@2.1.3
node-sass@4.13.1
node@12.16.2
报错信息以下:
Module build failed (from ./node_modules/thread-loader/dist/cjs.js):
Thread Loader (Worker 3)
this.getResolve is not a function
复制代码
暂时没有解决方案,将 sass-loader
降级到 v7.3.1
能够正常运行,相关 issue
使用 webpack4
二次打包的时候,咱们会发现比第一次快来很多,这是由于 webpack
内置 terser-webpack-plugin
来最小化 JS 文件,默认会启用多进程和缓存,第二次的时候直接读取项目下 node_modules/.cache/terser-webpack-plugin
目录,因此较第一次打包会快上很多
一样的咱们在使用 babel-loader
的时候,也能够将缓存启用,设置 cacheDirectory: true
便可
若是你想缓存其余 loader
的处理结果,你可使用 cache-loader
项目不够大,服务器逻辑核数(物理核心 * 每一个核心的线程数)不够多,不要使用多进程打包,反向优化说的就是我,使用 thread-loader
多进程打包后,在本地构建反而增长了近 40s
的时间,以下图:
这篇文章拖了好久,半个多月才写完,总结一下拖延的点:
HappyPack
)和冗余(terser-webpack-plugin
默认会启用 多进程)的部分,并且也没有实践的部分,顿时就以为有了本身的(这篇文章)存在有了意义;CI/CD
构建速度中位数 50s
左右,还算能够,抱着善始善终的态度写完了最后仍是提一下,worker
启动和进程间通讯的开销都不小,结合项目实际状况使用,不要为了用而用,项目质量比性能更重要。