webpack dll打包重復問題優(yōu)化的解決
關于webpack dll的使用,我這里不做過多介紹,網上都有,一擼一大把,今天我要說的是在使用dll plugin過程中出現(xiàn)的一個包依賴問題,這個問題導致打出來的包會包含重復的代碼。
優(yōu)化背景
最近在給公司項目優(yōu)化的時候,由于 內部CDN上傳文件大小限制了500K ,所以用了webpack dll來進行拆分打包,我將拆分的包分為三部分:
- vue生態(tài)包(
vue、vuex、vue-router、vuex-class、vue-class-component等周邊生態(tài)的庫) - vue插件包(
vee-validate、內部UI庫,圖片預覽等vue插件庫) - 第三方包(
axios、內部一些錯誤統(tǒng)計、上報,員工水印等這些脫離于vue的第三方庫)
三部分的包名分別是 vue.dll.js 、 plugin.dll.js 、 lib.dll.js ,這樣的好處是結構清晰,最重要的原因還是分解包的大小,降低到500K以內
但是在進行dll打包后,我驚奇地發(fā)現(xiàn) vue.dll.js 和 plugin.dll.js 中會包含重復的vue的dist代碼
下面是分別是前兩部分的bundle分析圖


可以看到這倆dll都包含了vue
那么要分析問題原因,先說一下我的DLL的配置吧
DLL配置
因為webpack支持多entry,所以一般多入口dll打包的話,首先會考慮一個webpack配置,多個entry入口,所以可能會出現(xiàn)
// webpack.dll.conf.js
module.exports = {
// 其他配置先省略
entry: {
vue: ['vue', 'vuex', 'vue-router', ...],
plugin: ['vee-validate', '內部UI庫', ...],
lib: ['axios', 'dayjs', ...]
},
plugins: [
new webpack.DllPlugin({
// dll.配置
})
]
}
但是親測這樣打包出來的文件依然有上述問題
所以結合我在之前公司所實踐的 webpack multi compiler 方式,參考webpack multi compiler ,我把webpack的配置一分為三,每一個dll包都有一個webpack配置,即
// config.js
exports.dll = [
{
name: 'vue',
libs: ['vue', 'vuex', 'vue-router', 'vuex-class', 'vue-class-component']
},
{
name: 'lib',
libs: [axios', 'dayjs', '第三方庫']
},
{
name: 'plugin',
libs: ['vee-validate', 'v-viewer', 'vue插件庫']
}
]
// webpack.dll.conf.js
module.exports = config.dll.map(function (vendor) {
return {
// 省略其他配置
entry: {
[vendor.name]: vendor.libs
},
plugins: [
new webpack.DllPlugin({
// dll.配置
})
]
}
})
// dll.js
const dllConfig = require('./webpack.dll.conf')
webpack(dllConfig, function (err, stats) {
if (err) throw err
// 處理stats相關信息
})
本以為這樣可以解決問題,但是現(xiàn)實卻是不能,所以得先分析一下問題所在
分析問題
經過仔細的排查,發(fā)現(xiàn)是由于內部UI庫中單獨引用了vue,即在庫中有
import Vue from 'vue' // ... // Vue相關操作 // Vue.prototype.$isServer等
這樣不管是多入口打包還是multi compiler方式下都會出現(xiàn)重復的包
解決方法
分析dll的原理,其實dll在打包的時候會將所有包含的庫做一個索引,寫在一個manifest文件中,然后在引用dll的時候只需要引用這個manifest文件即可
所以我就在想,如果plugin.dll.js依賴于vue.dll.js中的vue,那么是否可以先打包vue.dll.js,然后在打包plugin.dll.js的時候引用vue.dll.js呢?
心動不如行動,趕緊嘗試一下,做出如下修改
// config.js
exports.dll = [
{
name: 'vue',
libs: ['vue', 'vuex', 'vue-router', 'vuex-class', 'vue-class-component']
},
{
name: 'lib',
libs: [axios', 'dayjs', '第三方庫']
},
{
name: 'plugin',
libs: ['vee-validate', 'v-viewer', 'vue插件庫'],
ref: 'vue'
}
]
// webpack.dll.conf.js
// generate config
const gen = function (vendors) {
return vendors.map(function (item) {
const base = {
entry: {
[item.name]: item.libs
},
plugins: [
new webpack.DllPlugin({
// dll配置
})
]
}
if (item.ref) {
// 重點在這
// 在有ref的dll配置中,插入dll reference的plugin,內容是所依賴的dll包的manifest
base.plugins.push(new webpack.DllReferencePlugin({
// dll reference其他配置
manifest: '所依賴的dll包的manifest文件路徑'
}))
}
return base
})
}
// 根據(jù)是否有ref依賴項,區(qū)分base config和ref config
const [baseVendors, refVendors] = config.dll.vendors.reduce((config, v) => {
config[v.ref ? 1 : 0].push(v)
return config
}, [
[],
[]
])
// 生成base config
const getConfig = function () {
return gen(baseVendors)
}
// 生成ref config
const getRefConfig = function () {
return gen(refVendors)
}
module.exports = {
getConfig,
getRefConfig
}
// dll.js
const dllConfig = require('./webpack.dll.conf')
// 因為ref config依賴于base config,所以要保證base config先打包出來
const runWebpack = function (config) {
return new Promise(function (resolve) {
webpack(config, function (err, stats) {
if (err) throw err
// ...
resolve()
})
})
}
module.exports = function run () {
runWebpack(dllConfig.getConfig())
.then(() => runWebpack(dllConfig.getRefConfig()))
}
整體變成了如下結構

最關鍵的一步就是plugin.dl.js會引用vue.dll.js的manifest文件,這樣公共部分vue,就只會出現(xiàn)在vue.dll.js中了,plugin.dll.js打包后的bundle分析圖如下

可以很明顯地看到plugin.dll.js中已經沒有vue dist的身影了,包的體積得到了優(yōu)化:v:
可優(yōu)化項
上述優(yōu)化其實只考慮了一個依賴項,那么如果plugin.dll.js同時依賴于vue.dll.js和lib.dll.js呢?如果此時vue.dll.js也依賴于lib.dll.js呢?
如果出現(xiàn)上述情況,那么請先考慮dll包是否需要拆分?拆分是否合理?
然后再思考如何根據(jù)依賴順序思考打包順序,以及如果出現(xiàn)循環(huán)依賴,該怎么辦?
由于目前優(yōu)化需求中還未出現(xiàn)這種情況(這種情況應該很少很少很少見),所以我這邊就沒有解決這些問題了
總結
參考平常打包通過dll reference plugin來引用dll包的manifest的方式,如果多個dll包內出現(xiàn)了依賴,導致打包重復,那么是可以在依賴包中運用dll reference plugin來引用被依賴包的dll manifest,不過這樣的話,需要注意dll包的打包順序,被依賴包的dll要先于依賴包dll進行打包
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
詳述 Sublime Text 打開 GBK 格式中文亂碼的解決方法
這篇文章主要介紹了詳述 Sublime Text 打開 GBK 格式中文亂碼的解決方法,非常具有實用價值,需要的朋友可以參考下2017-10-10
在JavaScript中添加css樣式(js追加類)代碼示例
這篇文章主要給大家介紹了關于在JavaScript中如何添加css樣式,也就是js追加類的相關資料,JavaScript是一種廣泛應用于互聯(lián)網開發(fā)的編程語言,它能夠幫助網頁實現(xiàn)動態(tài)效果和交互性,需要的朋友可以參考下2024-01-01
Javascript:為input設置readOnly屬性(示例講解)
本篇文章主要是對Javascript中為input設置readOnly屬性的示例代碼進行了介紹。需要的朋友可以過來參考下,希望對大家有所幫助2013-12-12
js location.replace與location.reload的區(qū)別
js location.replace與location.reload的區(qū)別,經常能用的到,需要的朋友可以可以下。2010-09-09

