上一篇咱們講到,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
啓動和進程間通訊的開銷都不小,結合項目實際狀況使用,不要爲了用而用,項目質量比性能更重要。