詳解基于DllPlugin和DllReferencePlugin的webpack構(gòu)建優(yōu)化
一個(gè)基于vue-cli webpack2模板創(chuàng)建的項(xiàng)目.項(xiàng)目中使用到了vue+vue-router+axios+muse-ui+iview
現(xiàn)在構(gòu)建一次需要的時(shí)間大概是40s左右.真心受不了.雖然在開(kāi)發(fā)過(guò)程中,我們不太需要關(guān)心構(gòu)建時(shí)間.但是如果在開(kāi)發(fā)hybridApp時(shí),構(gòu)建的次數(shù)就會(huì)增多.
一般我們可以把項(xiàng)目分為三部分.
| 分類 | 說(shuō)明 | 變動(dòng)頻率 |
|---|---|---|
| vendor_library | 核心庫(kù) | 低 |
| vendor | 一般項(xiàng)目依賴 | 中等 |
| code | 業(yè)務(wù)邏輯 | 高 |
vendor_library:比如vue,vue-router,axios 這些變動(dòng)頻率極低的文件可以利用 DllPlugin 和 DllReferencePlugin 進(jìn)行預(yù)編譯.
vendor,code在開(kāi)發(fā)階段,每次構(gòu)建都需要編譯.但是一旦完成該次開(kāi)發(fā)任務(wù),應(yīng)該調(diào)整vendor 是否加入vendor_library.
BundleAnalyzerPlugin 的插件使用
BundleAnalyzerPlugin 是分析 Webpack 生成的包體組成并且以可視化的方式反饋給開(kāi)發(fā)者的插件。

vue已經(jīng)默認(rèn)集成了該插件. 如果你運(yùn)行 npm run build –report.就能看到當(dāng)前項(xiàng)目的依賴情況.然后做出相應(yīng)調(diào)整.
優(yōu)化方向
按需加載
muse-ui,iview 都提供了按需加載的方式,按照文檔調(diào)整即可.
| 分類 | 耗時(shí) | muse-ui | iview |
|---|---|---|---|
| before | 13256ms | 234KB | 337KB |
| after | 43211ms | 79KB | 75KB |
先看結(jié)果...你沒(méi)看錯(cuò),'優(yōu)化后',時(shí)間竟然變長(zhǎng)了...😂.不過(guò)這也正常,之前的依賴直接獲取的是dist目錄的文件,現(xiàn)在需要在src目錄下獲取.增加了編譯的過(guò)程.
但是文件大小的減少還是喜人的.當(dāng)然,這取決于項(xiàng)目中對(duì)模塊的使用程度.在我們這個(gè)項(xiàng)目中iview只使用了的四個(gè)控件.結(jié)果上看,顯然還是按需加載比較劃算.不過(guò)這個(gè)不算是時(shí)間上的優(yōu)化,只是因?yàn)閐ll可以解決構(gòu)建時(shí)間問(wèn)題,使按需加載變的更好用.
DllPlugin 和 DllReferencePlugin 預(yù)編譯資源模塊
Dll這個(gè)概念應(yīng)該是借鑒了Windows系統(tǒng)的dll。一個(gè)dll包,就是一個(gè)純純的依賴庫(kù),它本身不能運(yùn)行,是用來(lái)給你的app引用的。
打包dll的時(shí)候,Webpack會(huì)將所有包含的庫(kù)做一個(gè)索引,寫在一個(gè)manifest文件中,而引用dll的代碼(dll user)在打包的時(shí)候,只需要讀取這個(gè)manifest文件,就可以了。
這么一來(lái)有幾個(gè)好處:
Dll打包以后是獨(dú)立存在的,只要其包含的庫(kù)沒(méi)有增減、升級(jí),hash也不會(huì)變化,因此線上的dll代碼不需要隨著版本發(fā)布頻繁更新。
App部分代碼修改后,只需要編譯app部分的代碼,dll部分,只要包含的庫(kù)沒(méi)有增減、升級(jí),就不需要重新打包。這樣也大大提高了每次編譯的速度。
假設(shè)你有多個(gè)項(xiàng)目,使用了相同的一些依賴庫(kù),它們就可以共用一個(gè)dll。
網(wǎng)上抄的… 其實(shí)意思就是我們可以把項(xiàng)目的公共模塊,基本不會(huì)改動(dòng)的模塊.想我們剛才說(shuō)的定義為vendor_library的內(nèi)容,進(jìn)行預(yù)編譯編譯.以后在項(xiàng)目構(gòu)建過(guò)程中,vendor_library部分直接引用,就不需要再編譯了.
這也是為什么按需加載可以得到更好的使用,正常構(gòu)建流程,因?yàn)槭褂昧税葱杓虞d,會(huì)導(dǎo)致每次的構(gòu)建都比使用全量加載用時(shí)要長(zhǎng).而使用dll,核心庫(kù)只需要編譯一次,以后直接引用即可.
先來(lái)看一下改進(jìn)結(jié)果:
| 分類 | 耗時(shí) |
|---|---|
| before | 57192ms |
| after | 7890ms |
哈哈,有沒(méi)有快到飛起!??!
DllPlugin 和 DllReferencePlugin 使用
新建webpack.dll.conf.js文件
//webpack.dll.conf.js
process.env.NODE_ENV = 'production'
const path = require('path');
var utils = require('./utils')
var vueLoaderConfig = require('./vue-loader.conf')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
const webpack = require('webpack');
//vue項(xiàng)目默認(rèn)有一個(gè)static目錄.我就把導(dǎo)出目錄放在了static/dll/目錄下
const srcPath = path.join(__dirname, '../static/dll/');
//需要編譯的模塊
const vendors = ['vue/dist/vue.esm.js',
'vue-router',
'vue-localstorage',
'material-design-icons/iconfont/material-icons.css',
'iview/dist/styles/iview.css',
'iview/src/components/tag/tag.vue'
'muse-ui/src/appBar'
];
webpackConfig = {
entry: {
vendor: vendors
},
resolve: {
extensions: ['.js', '.vue', '.json']
},
module: {
loaders: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
{
test: /iview.src.*?js$/,
loader: 'babel-loader'
},
{
test: /muse-ui.src.*?js$/,
loader: 'babel-loader'
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
use: "css-loader"
})
},
{
test: /\.(woff2?|eot|ttf|otf|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
publicPath: './',
limit: 1000,
name: 'fonts/[name].[ext]'
}
}]
},
output: {
path: srcPath, // 輸出的路徑
filename: '[name].dll.js', // 輸出的文件,將會(huì)根據(jù)entry命名為vendor.dll.js
library: '[name]_library' // 暴露出的全局變量名
},
plugins: [
new ExtractTextPlugin({
filename: '[name].dll.css'
}),
new OptimizeCSSPlugin({
cssProcessorOptions: {
safe: true
}
}),
new webpack.optimize.UglifyJsPlugin({ // uglifjs壓縮
compress: {
warnings: false
}
}),
new webpack.DllPlugin({
path: path.join(srcPath, '[name]-mainfest.json'), // 描述依賴對(duì)應(yīng)關(guān)系的json文件
name: '[name]_library',
context: __dirname // 執(zhí)行的上下文環(huán)境,對(duì)之后DllReferencePlugin有用
})
]
}
if (process.env.npm_config_report) {
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
module.exports = webpackConfig;
其實(shí)這就是一個(gè)正常的構(gòu)建文件.根據(jù)你的項(xiàng)目進(jìn)行修改即可.唯一不同的是在plugins多了一個(gè)DllPlugin.他會(huì)生成一個(gè)描述依賴對(duì)應(yīng)關(guān)系的json文件.
static目錄如下:
|____dll | |____fonts | |____vendor-mainfest.json | |____vendor.dll.css | |____vendor.dll.js
修改模板index.html 根據(jù)你的構(gòu)建結(jié)果做修改.
//head 標(biāo)簽 <link type="text/css" rel="stylesheet" href="./static/dll/vendor.dll.css" rel="external nofollow" > //body 標(biāo)簽 <script src="./static/dll/vendor.dll.js"></script>
修改webpack.base.conf.js
plugins: [
...,
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('../static/dll/vendor-mainfest.json') // 指向生成的json文件
})
]
執(zhí)行
webpack --config ./build/webpack.dll.conf.js
你也可以將該語(yǔ)句放入npm run 中.'build:dll:report' 是為了優(yōu)化dll依賴關(guān)系,添加的另外一條命令.上文已經(jīng)提過(guò),我們可以借用BundleAnalyzerPlugin插件查看當(dāng)前包的依賴情況,和包體組成情況.
//package.json
"scripts":{
"build:dll": "webpack --config ./build/webpack.dll.conf.js",
"build:dll:report": "npm run build:dll --report"
}
npm run build …看看這次的構(gòu)建時(shí)間吧
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
JavaScript中函數(shù)的四種調(diào)用方式總結(jié)
這篇文章主要為大家詳細(xì)介紹了JavaScript中函數(shù)的四種調(diào)用方式,文中的示例代碼講解詳細(xì),對(duì)我們深入掌握J(rèn)avaScript有一定的幫助,需要的可以參考下2023-10-10
ES6中Set和Map數(shù)據(jù)結(jié)構(gòu),Map與其它數(shù)據(jù)結(jié)構(gòu)互相轉(zhuǎn)換操作實(shí)例詳解
這篇文章主要介紹了ES6中Set和Map數(shù)據(jù)結(jié)構(gòu),Map與其它數(shù)據(jù)結(jié)構(gòu)互相轉(zhuǎn)換操作,結(jié)合實(shí)例形式詳細(xì)分析了ES6中的Set和Map數(shù)據(jù)結(jié)構(gòu)的概念、原理、遍歷、去重等操作,以及Map與其它數(shù)據(jù)結(jié)構(gòu)互相轉(zhuǎn)換操作,需要的朋友可以參考下2019-02-02
一個(gè)頁(yè)面放2段圖片滾動(dòng)代碼出現(xiàn)沖突的問(wèn)題如何解決
這是一段調(diào)用圖片流動(dòng)的代碼?為什么我在首頁(yè)同時(shí)復(fù)制出二段代碼后圖片不能流動(dòng)顯示了?遇此問(wèn)題很是疑惑,于是搜集整理一些實(shí)用技巧以解大伙們的燃眉之急,需要了解的朋友可以參考下2012-12-12
解決layer.open后laydate失效的問(wèn)題
今天小編就為大家分享一篇解決layer.open后laydate失效的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-09-09
js中常見(jiàn)切割截取字符串的幾種方法小結(jié)
前端開(kāi)發(fā)中,字符串處理是比較常見(jiàn)的,下面這篇文章主要給大家介紹了關(guān)于js中常見(jiàn)切割截取字符串的幾種方法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09
JS簡(jiǎn)單添加元素新節(jié)點(diǎn)的方法示例
這篇文章主要介紹了JS簡(jiǎn)單添加元素新節(jié)點(diǎn)的方法,結(jié)合實(shí)例形式分析了javascript針對(duì)頁(yè)面元素節(jié)點(diǎn)的創(chuàng)建、添加、克隆等相關(guān)操作技巧,需要的朋友可以參考下2018-02-02

