溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何解決webpack dll打包重復(fù)問題

發(fā)布時間:2021-08-02 14:44:12 來源:億速云 閱讀:168 作者:小新 欄目:web開發(fā)

這篇文章主要介紹了如何解決webpack dll打包重復(fù)問題,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

關(guān)于webpack dll的使用,我這里不做過多介紹,網(wǎng)上都有,一擼一大把,今天我要說的是在使用dll plugin過程中出現(xiàn)的一個包依賴問題,這個問題導(dǎo)致打出來的包會包含重復(fù)的代碼。

優(yōu)化背景

最近在給公司項目優(yōu)化的時候,由于 內(nèi)部CDN上傳文件大小限制了500K ,所以用了webpack dll來進行拆分打包,我將拆分的包分為三部分:

  • vue生態(tài)包( vue 、 vuexvue-router 、 vuex-class 、 vue-class-component 等周邊生態(tài)的庫)

  • vue插件包( vee-validate 、內(nèi)部UI庫,圖片預(yù)覽等vue插件庫)

  • 第三方包( axios 、內(nèi)部一些錯誤統(tǒng)計、上報,員工水印等這些脫離于vue的第三方庫)

三部分的包名分別是 vue.dll.js 、 plugin.dll.js 、 lib.dll.js ,這樣的好處是結(jié)構(gòu)清晰,最重要的原因還是分解包的大小,降低到500K以內(nèi)

但是在進行dll打包后,我驚奇地發(fā)現(xiàn) vue.dll.jsplugin.dll.js 中會包含重復(fù)的vue的dist代碼

下面是分別是前兩部分的bundle分析圖

如何解決webpack dll打包重復(fù)問題

如何解決webpack dll打包重復(fù)問題

可以看到這倆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', '內(nèi)部UI庫', ...],
    lib: ['axios', 'dayjs', ...]
  },
 plugins: [
  new webpack.DllPlugin({
   // dll.配置
  })
 ]
}

但是親測這樣打包出來的文件依然有上述問題

所以結(jié)合我在之前公司所實踐的 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相關(guān)信息
})

本以為這樣可以解決問題,但是現(xiàn)實卻是不能,所以得先分析一下問題所在

分析問題

經(jīng)過仔細的排查,發(fā)現(xiàn)是由于內(nèi)部UI庫中單獨引用了vue,即在庫中有

import Vue from 'vue'

// ...
// Vue相關(guān)操作
// Vue.prototype.$isServer等

這樣不管是多入口打包還是multi compiler方式下都會出現(xiàn)重復(fù)的包

解決方法

分析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,內(nèi)容是所依賴的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()))
}

整體變成了如下結(jié)構(gòu)

如何解決webpack dll打包重復(fù)問題

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

如何解決webpack dll打包重復(fù)問題

可以很明顯地看到plugin.dll.js中已經(jīng)沒有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)這種情況(這種情況應(yīng)該很少很少很少見),所以我這邊就沒有解決這些問題了

感謝你能夠認真閱讀完這篇文章,希望小編分享的“如何解決webpack dll打包重復(fù)問題”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識等著你來學(xué)習(xí)!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI