webpack dll打包重复问题优化的解决

关于webpack dll的使用,我这里不做过多介绍,网上都有,一撸一大把,今天我要说的是在使用dll plugin过程中出现的一个包依赖问题,这个问题导致打出来的包会包含重复的代码。

优化背景

最近在给公司项目优化的时候,由于 内部CDN上传文件大小限制了500K ,所以用了webpack dll来进行拆分打包,我将拆分的包分为三部分:

vue生态包( vue 、 vuex 、 vue-router 、 vuex-class 、 vue-class-component 等周边生态的库)

vue插件包( vee-validate 、内部UI库,图片预览等vue插件库)

第三方包( axios 、内部一些错误统计、上报,员工水印等这些脱离于vue的第三方库)

三部分的包名分别是 vue.dll.js 、 plugin.dll.js 、 lib.dll.js ,这样的好处是结构清晰,最重要的原因还是分解包的大小,降低到500K以内

但是在进行dll打包后,我惊奇地发现 vue.dll.js 和 plugin.dll.js 中会包含重复的vue的dist代码

下面是分别是前两部分的bundle分析图

webpack dll打包重复问题优化的解决

webpack dll打包重复问题优化的解决

可以看到这俩dll都包含了vue

那么要分析问题原因,先说一下我的DLL的配置吧

DLL配置

因为webpack支持多entry,所以一般多入口dll打包的话,首先会考虑一个webpack配置,多个entry入口,所以可能会出现

// 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的配置一分为三,每一个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相关信息 })

本以为这样可以解决问题,但是现实却是不能,所以得先分析一下问题所在

分析问题

经过仔细的排查,发现是由于内部UI库中单独引用了vue,即在库中有

import Vue from 'vue' // ... // Vue相关操作 // Vue.prototype.$isServer等

这样不管是多入口打包还是multi compiler方式下都会出现重复的包

解决方法

分析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 }) } // 根据是否有ref依赖项,区分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 }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/51ced6f65d18d04930c79452ccf6f75a.html