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 相关文章推荐
javascript学习笔记(十) js对象 继承
Jun 19 Javascript
浅析LigerUi开发中谨慎载入common.css文件
Jul 09 Javascript
Ext中下拉列表ComboBox组件store数据格式用法介绍
Jul 15 Javascript
如何实现修改密码时密码框显示保存到cookie的密码
Dec 10 Javascript
javascript 按键事件(兼容各浏览器)
Dec 20 Javascript
js返回上一页并刷新的多种实现方法
Feb 26 Javascript
jQuery 写的简单打字游戏可以提示正确和错误的次数
Jul 01 Javascript
jQuery使用ajax方法解析返回的json数据功能示例
Jan 10 Javascript
常用的javascript设计模式
Jan 11 Javascript
使用JavaScriptCore实现OC和JS交互详解
Mar 28 Javascript
基于$.ajax()方法从服务器获取json数据的几种方式总结
Jan 31 Javascript
React自定义hook的方法
Jun 25 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
PHP的HTTP客户端Guzzle简单使用方法分析
2019/10/30 PHP
分享一个自己写的table表格排序js插件(高效简洁)
2011/10/29 Javascript
使用jQuery fancybox插件打造一个实用的数据传输模态弹出窗体
2013/01/15 Javascript
jquery使用ColorBox弹出图片组浏览层实例演示
2013/03/14 Javascript
利用jQuery的deferred对象实现异步按顺序加载JS文件
2013/03/17 Javascript
JS 打印功能代码可实现打印预览、打印设置等
2014/10/31 Javascript
使用Sticker.js实现贴纸效果
2015/01/28 Javascript
详解AngularJS控制器的使用
2016/03/09 Javascript
jQuery操作之效果详解
2017/05/19 jQuery
Angular.js项目中使用gulp实现自动化构建以及压缩打包详解
2017/07/19 Javascript
解决element UI 自定义传参的问题
2018/08/22 Javascript
20道JS原理题助你面试一臂之力(必看)
2019/07/22 Javascript
基于vue实现图片验证码倒计时60s功能
2019/12/10 Javascript
在Echarts图中给坐标轴加一个标识线markLine
2020/07/20 Javascript
JavaScript 判断数据类型的4种方法
2020/09/11 Javascript
vue-cli3自动消除console.log()的调试信息方式
2020/10/21 Javascript
[06:42]DOTA2每周TOP10 精彩击杀集锦vol.1
2014/06/25 DOTA
[17:36]VG战队纪录片
2014/08/21 DOTA
[00:32]10月24、25日 辉夜杯外卡赛附加赛开赛!
2015/10/23 DOTA
深入理解Python中字典的键的使用
2015/08/19 Python
python获取多线程及子线程的返回值
2017/11/15 Python
学习Python3 Dlib19.7进行人脸面部识别
2018/01/24 Python
python中的随机函数random的用法示例
2018/01/27 Python
Python实现将多个空格换为一个空格.md的方法
2018/12/20 Python
python框架flask入门之环境搭建及开启调试
2020/06/07 Python
css3旋转木马_动力节点Java学院整理
2017/07/12 HTML / CSS
Canvas实现贝赛尔曲线轨迹动画的示例代码
2019/04/25 HTML / CSS
Sephora丝芙兰澳洲官方网站:国际知名化妆品购物
2016/10/27 全球购物
新奥尔良珠宝:Mignon Faget
2020/11/23 全球购物
在浏览器端如何得到服务器端响应的XML数据
2012/11/24 面试题
《高尔基和他的儿子》教学反思
2014/04/09 职场文书
学校四群教育实施方案
2014/06/12 职场文书
工程承包协议书范本
2014/09/29 职场文书
优秀创业计划书分享
2019/07/19 职场文书
tensorflow学习笔记之tfrecord文件的生成与读取
2021/03/31 Python
前端传参数进行Mybatis调用mysql存储过程执行返回值详解
2022/08/14 MySQL