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


Posted in Javascript onOctober 10, 2018

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

优化背景

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

  • vue生态包( vuevuexvue-routervuex-classvue-class-component 等周边生态的库)
  • vue插件包( vee-validate 、内部UI库,图片预览等vue插件库)
  • 第三方包( axios 、内部一些错误统计、上报,员工水印等这些脱离于vue的第三方库)

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

但是在进行dll打包后,我惊奇地发现 vue.dll.jsplugin.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 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
}
// 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()))
}

整体变成了如下结构

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

最关键的一步就是plugin.dl.js会引用vue.dll.js的manifest文件,这样公共部分vue,就只会出现在vue.dll.js中了,plugin.dll.js打包后的bundle分析图如下

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

可以很明显地看到plugin.dll.js中已经没有vue dist的身影了,包的体积得到了优化:v:

可优化项

上述优化其实只考虑了一个依赖项,那么如果plugin.dll.js同时依赖于vue.dll.js和lib.dll.js呢?如果此时vue.dll.js也依赖于lib.dll.js呢?

如果出现上述情况,那么请先考虑dll包是否需要拆分?拆分是否合理?

然后再思考如何根据依赖顺序思考打包顺序,以及如果出现循环依赖,该怎么办?

由于目前优化需求中还未出现这种情况(这种情况应该很少很少很少见),所以我这边就没有解决这些问题了

总结

参考平常打包通过dll reference plugin来引用dll包的manifest的方式,如果多个dll包内出现了依赖,导致打包重复,那么是可以在依赖包中运用dll reference plugin来引用被依赖包的dll manifest,不过这样的话,需要注意dll包的打包顺序,被依赖包的dll要先于依赖包dll进行打包

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery中的bind绑定事件与文本框改变事件的临时解决方法
Aug 13 Javascript
从零学JS之你需要了解的几本书
May 19 Javascript
js+HTML5实现canvas多种颜色渐变效果的方法
Jun 05 Javascript
jQuery实现动态删除LI的方法
May 30 jQuery
JavaScript实现图片无缝滚动效果
Jul 07 Javascript
详解vue + vuex + directives实现权限按钮的思路
Oct 24 Javascript
vue 运用mock数据的示例代码
Nov 07 Javascript
vue2 mint-ui loadmore实现下拉刷新,上拉更多功能
Mar 21 Javascript
JavaScript中变量提升与函数提升经典实例分析
Jul 26 Javascript
浅谈JavaScript中的“!!”作用
Aug 03 Javascript
vue-以文件流-blob-的形式-下载-导出文件操作
Aug 07 Javascript
vue 子组件watch监听不到prop的解决
Aug 09 Javascript
4个顶级JavaScript高级文本编辑器
Oct 10 #Javascript
Koa代理Http请求的示例代码
Oct 10 #Javascript
解决js相同的正则多次调用test()返回的值却不同的问题
Oct 10 #Javascript
jQuery 获取除某指定对象外的其他对象 ( :not() 与.not())
Oct 10 #jQuery
微信小程序自定义组件的实现方法及自定义组件与页面间的数据传递问题
Oct 09 #Javascript
从零开始封装自己的自定义Vue组件
Oct 09 #Javascript
vue axios 简单封装以及思考
Oct 09 #Javascript
You might like
vBulletin HACK----显示话题大小和打开新窗口于论坛索引页
2006/10/09 PHP
php UTF8 文件的签名问题
2009/10/30 PHP
php实现telnet功能示例
2014/04/08 PHP
php实例分享之二维数组排序
2014/05/15 PHP
php自定义中文字符串截取函数substr_for_gb2312及substr_for_utf8示例
2016/05/28 PHP
php使用函数pathinfo()、parse_url()和basename()解析URL
2016/11/25 PHP
关于PHP通用返回值设置方法
2017/03/31 PHP
php爬取天猫和淘宝商品数据
2018/02/23 PHP
JavaScript函数、方法、对象代码
2008/10/29 Javascript
在JQuery dialog里的服务器控件 事件失效问题
2010/12/08 Javascript
点击进行复制的JS代码实例
2013/08/23 Javascript
如何解决Jquery库及其他库之间的$命名冲突
2013/09/15 Javascript
js的参数有长度限制吗?发现不能超过2083个字符
2014/04/20 Javascript
javascript中的throttle和debounce浅析
2014/06/06 Javascript
JavaScript的内存释放问题详解
2015/01/21 Javascript
JavaScript中return false的用法
2015/03/12 Javascript
jQuery解析json格式数据简单实例
2016/01/22 Javascript
javascript计时器编写过程与实现方法
2016/02/29 Javascript
在js里怎么实现Xcode里的callFuncN方法(详解)
2016/11/05 Javascript
jquery购物车结算功能实现方法
2020/10/29 Javascript
Bootstrap CSS组件之面包屑导航(breadcrumb)
2016/12/17 Javascript
你真的了解BOM中的history对象吗
2017/02/13 Javascript
JS仿淘宝搜索框用户输入事件的实现
2017/06/19 Javascript
Bootstrap简单实用的表单验证插件BootstrapValidator用法实例详解
2020/03/29 Javascript
原生js实现弹窗消息动画
2020/11/20 Javascript
Python实现读取邮箱中的邮件功能示例【含文本及附件】
2017/08/05 Python
Python使用numpy产生正态分布随机数的向量或矩阵操作示例
2018/08/22 Python
浅谈python 中类属性共享的问题
2019/07/02 Python
Python第三方包之DingDingBot钉钉机器人
2020/04/09 Python
django queryset 去重 .distinct()说明
2020/05/19 Python
CSS3 animation实现简易幻灯片轮播特效
2016/09/27 HTML / CSS
巴西图书和电子产品购物网站:Saraiva
2017/06/07 全球购物
卡西欧B级产品官方网站:Casio Outlet
2018/05/22 全球购物
销售自我评价
2013/10/22 职场文书
关于CSS浮动与取消浮动的问题
2021/06/28 HTML / CSS
《黑岩★★射手 DAWN FALL》BD发售宣传CM公开
2022/04/04 日漫