項目打包構建優化
優化項目: vue3-elm-master
方法
- 查找并診斷性能瓶頸
- 構建速度分析: 影響構建性能和開發效率. speed-measure-webpack-plugin
- 構建體積分析: 影響頁面訪問性能 webpack-bundle-analyzer
- 構建性能優化常用方法:
- 通過多進程加快構建速度
thread-loader - 通過分包減小構建目標容量(某些文件太大,就分成多個目標)
DllPlugin - 減少構建目標加快構建速度(文件太小,數量有多的, 合并文件)
- 通過多進程加快構建速度
1. speed-measure-webpack-plugin 分析項目構建速度
用來分析各個loader, plugin花費的時間.
// vue-cli的情況
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin({
disable: process.env.MEASURE !== "true", // 是否使用 速度測試
outputFormat: "humanVerbose", // 輸出內容格式
});
module.exports = {
// smp.wrap(webpackConfig), 在vue.config.js里包裹configureWebpack, 直接使用webpack的話, 就是包裹webpackConfig.
configureWebpack: smp.wrap({
devtool: "eval-source-map",
})
}
// 直接使用webpack的情況
const webpackConfig = smp.wrap(webpackConfig);
var compiler = webpack(webpackConfig)
2. webpack-bundle-analyzer 檢測打包后的文件的體積的插件
配置項 analyzerMode:
1. "serve" 啟動后通過服務器開啟瀏覽器頁面
2. "static" 將檢測結果生成一個html文件, 默認為 dist/report.html
3. "json" 將檢測結果生成一個json文件
4. "disabled" 不啟動檢測.

// 檢測構建文件體積的插件
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
// webpack的配置
{
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: process.env.MEASURE === "true" ? "server" : "disabled",
}),
]
}
3. 用thread-loader,啟動多進程構建.
thread-loader, 放到所有loader的前面, 可以開啟多進程構建.
- 由于啟動進程也需要時間, 所以如果構建本身就夠快的情況下, 多進程反而會更耗費時間. 需要本身就很耗費時間的情況下, 多進程才有意義.
- worker屬性: 進程數量.
- 以當前項目為例, 未開多進程,構建項目5359ms, 開了5個進程, 5037ms(有用但不多).
- vue-cli的parallel配置項, 是否開多進程編譯, 盡在生產模式
production生效.
parallel: true, build時間: 8553ms,
parallel: falsebuild時間: 8671ms
{
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: "thread-loader",
options: {
// 進程數量
worker: 5,
}
}
],
}
]
},
}
4. DllPlugin 分包
對于變化幾率很小的一些第三方包(比如vue, vux, vue-router), 沒必要每次build都打包一次. 可以把這些單獨
抽出來打包好(一般不超過300kb).
webpack本身是要體現出模塊之間的依賴關系, 當我們將一些包抽離出來后, 維護之前的依賴關系就需要manifest.json 這個文件,將vue, vue-router, vuex等基礎包打包成一個文件,也就是使用DllPlugin進行分包,
DllReferencePlugin對manifest.json引用. manifest.json是對分離出來的包的描述
具體步驟
- 分包: 定義webpack.dll.config.js 使用DllPlugin配置分包, 定義script命令,完成分包
- 排除分包: 在vue.config.js中, 使用DllReferencePlugin引用manifest文件排除分包
- 引用dll: 使用add-asset-html-webpack-plugin 引用分包文件
5. 分包
分包原因:
包太大.導致請求緩慢.
分包方案:
對于變化幾率很小的一些第三方包(比如vue, vux, vue-router), 沒必要每次build都打包一次. 可以把這些單獨
抽出來打包成一個文件,作為靜態文件(一般不超過300kb).
分包好處:
- 這樣不用每次打包的時候重復打包,減少打包時間
- 減少index.js的文件大小.分出300kb, 降低頁面的請求時間.
6. 分包方案
- DllPlugin分包
用DllPlugin, 把vue,vuex, vue-router打包成一個js文件包vue.dll.js. 作為一個靜態文件存放到項目中
執行webpack --config build/webpack.dll.config.js,會生成
dll文件夾
- vue.dll.js 打包好的vue,vuex,vue-router總和的文件.對外輸出
vue_xxxxxxx作為入口. - vue-manifest.json 記錄
vue.dll.js信息的文件, 給webpack用, webpack打包時要知道哪些文件dll打包了,打包的文件怎么引用. - vue.dll.js.LICENSE.txt 分享權限聲明文件, 無實際作用.
// webpack.dll.config.js
const path = require("path");
const webpack = require("webpack");
const dllPath = "../dll";
module.exports = {
mode: "production",
entry: {
// 入口文件, vue, vue-router, vuex, 命名為一個vue
vue: ['vue', 'vue-router', 'vuex'],
// 將 better-scroll, 命名為scroll
// scroll: ["better-scroll"],
},
output: {
// 輸出文件路徑
path: path.join(__dirname, dllPath),
// 輸出的文件名, name就是entry里的"vue", "scroll", 最后生成 vue.dll.js, scroll.dll.js
filename: '[name].dll.js',
// library是在全局聲明一個變量. 變量的內容就是entry里的內容.
// 具體在這個案例就是聲明一個 `vue_xxxxxxxx`的變量.里面有{vue: xxx, vuex: xxx, vue-router: xxxx}
// 通過這種方式來獲取entry里的內容.
library: `[name]_[hash]`,
},
plugins: [
new webpack.DllPlugin({
//生成vue-manifest.json文件,記錄vue.dll.js里都打包了哪些文件
// 給webpack build打包用, 用來排除vue,vuex,vue-router
path: path.join(__dirname, dllPath, '[name]-manifest.json'),
// 用來記錄 相關對象的導出方式(比如獲取vue對象方式: vue_xxxxxxxx.vue ) , 和 output.library想同.
name: '[name]_[hash]',
context: process.cwd(),
})
]
}
- 由于vue,vuex, vue-router打成一個包了, 那么webpack build的時候, 就要把vue,vuex, vue-router去掉.
const path = require("path");
const webpack = require("webpack");
{
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
// 獲取dll打包的信息文件, 后續webpack打包時就不會打包manifest.json里記錄的文件了.
manifest: path.resolve(__dirname, "./dll/vue-manifest.json"),
})
]
}
- 默認生成的index.html是不會引入
vue.dll.js的, 需要用add-asset-html-webpack-plugin插件創建一個script標簽把vue.dll.js導入到index.html里
按理說如下所示使用即可, 但是實際操作中,未生效. 網上提示需要 Html-Webpack-Plugin@3.2.0, 我未使用此種方案
const AddAssetHtmlWebpackPlugin = require("add-asset-html-webpack-plugin");
{
plugins: [
new AddAssetHtmlWebpackPlugin({
filepath: path.resolve(__dirname, './dll/vue.dll.js'),
})
]
}
我的方案:
- htmlWebpackPlugin指定了一個index.html模板, 在index.html模板中直接用script引入
vue.dll.js文件 - 用
copy-webpack-plugin把dll/vue.dll.js直接復制到dist/js/vue.dll.js.
// index.html直接加入這一行
<script src="js/vue.dll.js"></script>
// vue.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
export default {
configureWebpack: {
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, './public/index.html')
}),
new CopyWebpackPlugin({
patterns: [{
from: path.resolve(__dirname, "./dll/vue.dll.js"),
to: path.resolve(__dirname, "./dist/js/vue.dll.js"),
}]
}),
]
}
}
7. cache緩存
webpack的cache緩存屬性. 開發環境默認 true, 生產環境禁用.
一般是測試環境build代碼時使用. 用jenkins在線打包時, 第一次慢,第二次快用的就是cache.
生成的緩存文件
- 0.pack : 應該是 node_modules里的總和文件
- index.pack : 應該是業務的總和文件.
build時間:
- 不適用緩存 17838ms
- 使用緩存 1548ms
export default {
configureWebpack: {
// 使用緩存, 開發環境默認 true, 生產環境禁用.
cache: {
type: 'filesystem',
cacheDirectory: path.resolve(__dirname, "node_modules/.cache_temp"),
},
}
}
8. image-webpack-loader 圖片壓縮
插件下載: cnpm i -D image-webpack-plugin, 用npm下載會報錯
9. purgecss-webpack-plugin css 去掉未使用的css
該插件會把css文件里有的, 但是在html中未使用的css類去掉.達到壓縮css文件的目的.
未壓縮前app.css: 131kb. 壓縮后 6kb;
插件下載: cnpm i -D purgecss-webpack-plugin, 用npm下載會報錯
const glob = require("glob");
// 去掉未使用的css的插件
const { PurgeCSSPlugin } = require("purgecss-webpack-plugin");
const PATHS = {
src: path.join(__dirname, "src"),
}
export default {
plugins: [
new PurgeCSSPlugin({
paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }),
})
]
}
浙公網安備 33010602011771號