详解如何webpack使用DllPlugin


Posted in Javascript onSeptember 30, 2018

前言

(时光飞逝,转眼又偷懒了一个多月)

什么是DLL

DLL(Dynamic Link Library)文件为动态链接库文件,在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件,放置于系统中。当我们执行某一个程序时,相应的DLL文件就会被调用。

举个例子:很多产品都用到螺丝,但是工厂在生产不同产品时,不需要每次连带着把螺丝也生产出来,因为螺丝可以单独生产,并给多种产品使用。在这里螺丝的作用就可以理解为是dll。

为什么要使用Dll

通常来说,我们的代码都可以至少简单区分成业务代码和第三方库。如果不做处理,每次构建时都需要把所有的代码重新构建一次,耗费大量的时间。然后大部分情况下,很多第三方库的代码并不会发生变更(除非是版本升级),这时就可以用到dll:把复用性较高的第三方模块打包到动态链接库中,在不升级这些库的情况下,动态库不需要重新打包,每次构建只重新打包业务代码。

还是上面的例子:把每次构建,当做是生产产品的过程,我们把生产螺丝的过程先提取出来,之后我们不管调整产品的功能或者设计(对应于业务代码变更),都不必重复生产螺丝(第三方模块不需要重复打包);除非是产品要使用新型号的螺丝(第三方模块需要升级),才需要去重新生产新的螺丝,然后接下来又可以专注于调整产品本身。

基本用法

使用dll时,可以把构建过程分成dll构建过程和主构建过程(实质也就是如此),所以需要两个构建配置文件,例如叫做webpack.config.jswebpack.dll.config.js

1. 使用DLLPlugin打包需要分离到动态库的模块

DllPluginwebpack内置的插件,不需要额外安装,直接配置webpack.dll.config.js文件:

module.exports = {=
 entry: {
  // 第三方库
  react: ['react', 'react-dom', 'react-redux']
 },
 output: {
  // 输出的动态链接库的文件名称,[name] 代表当前动态链接库的名称,
  filename: '[name].dll.js',
  path: resolve('dist/dll'),
  // library必须和后面dllplugin中的name一致 后面会说明
  library: '[name]_dll_[hash]'
 },
 plugins: [
 // 接入 DllPlugin
  new webpack.DllPlugin({
   // 动态链接库的全局变量名称,需要和 output.library 中保持一致
   // 该字段的值也就是输出的 manifest.json 文件 中 name 字段的值
   name: '[name]_dll_[hash]',
   // 描述动态链接库的 manifest.json 文件输出时的文件名称
   path: path.join(__dirname, 'dist/dll', '[name].manifest.json')
  }),
 ]
}

我们先来看看,这一步到底做了什么。执行:webpack --config webpack.dll.config,然后到指定的输出文件夹查看输出:

  • react.dll文件里是使用数组保存的模块,索引值就作为id;
  • react.manifest.json文件里,是用来描述对应的dll文件里保存的模块

里暴露出刚刚构建的所有模块,如下:

{
 "name":"react_dll_553e24e2c44987d2578f",
 "content":{
  "./node_modules/webpack/node_modules/process/browser.js":{"id":0,"meta":{}},"./node_modules/react/node_modules/fbjs/lib/invariant.js":{"id":1,"meta":{}},"./node_modules/react/lib/Object.assign.js":{"id":2,"meta":{}},"./node_modules/react/node_modules/fbjs/lib/warning.js":{"id":3,"meta":{}}
  //省略相似代码
 }
}

2. 在主构建配置文件使用动态库文件

webpack.config中使用dll要用到DllReferencePlugin,这个插件通过引用 dll 的 manifest 文件来把依赖的名称映射到模块的 id 上,之后再在需要的时候通过内置的 webpack_require 函数来 require 他们.

new webpack.DllReferencePlugin({
  context: __dirname,
  manifest: require('./dist/dll/react.manifest.json')
 }),

第一步产出的manifest文件就用在这里,给主构建流程作为查找dll的依据:DllReferencePlugin去 manifest.json 文件读取 name 字段的值,把值的内容作为在从全局变量中获取动态链接库中内容时的全局变量名,因此:在 webpack_dll.config.js 文件中,DllPlugin 中的 name 参数必须和 output.library 中保持一致。

3. 在入口文件引入dll文件。

生成的dll暴露出的是全局函数,因此还需要在入口文件里面引入对应的dll文件。

<body>
 <div id="app"></div>
 <!--引用dll文件-->
 <script src="../../dist/dll/react.dll.js" ></script>
</body>

作用

首先从前面的介绍,至少可以看出dll的两个作用

分离代码,业务代码和第三方模块可以被打包到不同的文件里,这个有几个好处:

  1. 避免打包出单个文件的大小太大,不利于调试
  2. 将单个大文件拆成多个小文件之后,一定情况下有利于加载(不超出浏览器一次性请求的文件数情况下,并行下载肯定比串行快)

提升构建速度。第三方库没有变更时,由于我们只构建业务相关代码,相比全部重新构建自然要快的多。

注意事项

从前面可以看到dll带来的优点,但并不意味着我们就应该把除业务代码外的所有代码全部都丢到dll中,举一个例子:
1.对于lodash这种第三方库,正确的用法是只去import所需的函数(用什么引什么),例如:

// 正确用法
import isPlainObject from 'lodash/isPlainObject'

//错误用法
import { isPlainObject } from 'lodash'

这两种写法的差别在于,打包时webpack会根据引用去打包依赖的内容,所以第一种写法,webpack只会打包lodash的isPlainObject库,第二种写法却会打包整个lodash。现在假设在项目中只是用到不同模块对lodash里的某几个函数并且没有对于某个函数重复使用非常多次,那么这时候把lodash添加到dll中,带来的收益就并不明显,反而导致2个问题:

  1. 由于打包了整个lodash,而导致打包后的文件总大小(注意是总大小)比原先还要大
  2. 在dll打包太多内容也需要耗费时间,虽然我们一般只在第三方模块更新之后才进行重新预编译(就是dll打包的过程),但是如果这个时间太长的话体验也不好、

实践与反思

放一张自己在一个比较大的项目中单纯使用dll之后的收益,提取的内容是 react相关的第三方库,和fish组件,构建时间从120s降低到80s左右(当然这个时间还是有点恐怖),构建前appjs的大小是680kb,拆分业务代码和第三方代码分别是400kb和380kb(这就是拆分后大小大于拆分前大小的例子),从这一点来看,对于常见第三方库是否要放进dll可能比较明确(比如react系列打包一般肯定不亏),但是还有一些就要结合具体的项目内容来进行判断和取舍。(强烈推荐使用webpack-bundle-analyzer插件进行性能分析)

详解如何webpack使用DllPlugin

详解如何webpack使用DllPlugin

详解如何webpack使用DllPlugin

总结

本文介绍了Dllplugin的思想,基本用法和应用场景(关于使用的部分更详细的内容可以看官方文档),结合个人的一些实践经验,对于常见第三方库是否要放进dll可能比较明确(比如react系列打包一般肯定不亏),但是还有一些就要结合具体的项目内容来判断,例如我上面的实践的例子就说明目前的拆分还不够好。这一块也欢迎大家一起探讨。

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

Javascript 相关文章推荐
js中将URL中的参数提取出来作为对象的实现代码
Aug 16 Javascript
CodeMirror2 IE7/IE8 下面未知运行时错误的解决方法
Mar 29 Javascript
vue.js内部自定义指令与全局自定义指令的实现详解(利用directive)
Jul 11 Javascript
js学习总结之DOM2兼容处理this问题的解决方法
Jul 27 Javascript
Angular模板表单校验方法详解
Aug 11 Javascript
利用jqprint插件打印页面内容的实现方法
Jan 09 Javascript
JointJS流程图的绘制方法
Dec 03 Javascript
vue实现员工信息录入功能
Jun 11 Javascript
vue $mount 和 el的区别说明
Sep 11 Javascript
vue使用exif获取图片经纬度的示例代码
Dec 11 Vue.js
jQuery实现手风琴特效
Jan 11 jQuery
ReactRouter的实现方法
Jan 25 Javascript
浅谈angular2子组件的事件传递(任意组件事件传递)
Sep 30 #Javascript
vue-router 手势滑动触发返回功能
Sep 30 #Javascript
Vue CLI3 开启gzip压缩文件的方式
Sep 30 #Javascript
JS数组实现分类统计实例代码
Sep 30 #Javascript
浅谈微信页面入口文件被缓存解决方案
Sep 29 #Javascript
vue实现弹框遮罩点击其他区域弹框关闭及v-if与v-show的区别介绍
Sep 29 #Javascript
vue使用v-for实现hover点击效果
Sep 29 #Javascript
You might like
BBS(php &amp; mysql)完整版(八)
2006/10/09 PHP
php实现用于删除整个目录的递归函数
2015/03/16 PHP
Zend Framework教程之Zend_Helpers动作助手ViewRenderer用法详解
2016/07/20 PHP
php微信开发之图片回复功能
2018/06/14 PHP
window.name代替cookie的实现代码
2010/11/28 Javascript
jquery ztree实现下拉树形框使用到了json数据
2014/05/14 Javascript
js实现C#的StringBuilder效果完整实例
2015/12/22 Javascript
jQuery Easyui学习之datagrid 动态添加、移除editor
2016/01/27 Javascript
基于javascript实现tab切换特效
2016/03/29 Javascript
利用jsonp跨域调用百度js实现搜索框智能提示
2016/08/24 Javascript
利用js获取下拉框中所选的值
2016/12/01 Javascript
JavaScript mixin实现多继承的方法详解
2017/03/30 Javascript
bootstrap timepicker在angular中取值并转化为时间戳
2017/06/13 Javascript
node中Express 动态设置端口的方法
2017/08/04 Javascript
微信小程序promsie.all和promise顺序执行
2017/10/27 Javascript
浅析java线程中断的办法
2018/07/29 Javascript
微信小程序—setTimeOut定时器的问题及解决
2019/07/26 Javascript
VUE中V-IF条件判断改变元素的样式操作
2020/08/09 Javascript
JavaScript实现复选框全选和取消全选
2020/11/20 Javascript
python实现dnspod自动更新dns解析的方法
2014/02/14 Python
python读取浮点数和读取文本文件示例
2014/05/06 Python
简单介绍使用Python解析并修改XML文档的方法
2015/10/15 Python
Python新手们容易犯的几个错误总结
2017/04/01 Python
python计算auc指标实例
2017/07/13 Python
Python设计模式之MVC模式简单示例
2018/01/10 Python
浅谈tensorflow中几个随机函数的用法
2018/07/27 Python
说说如何遍历Python列表的方法示例
2019/02/11 Python
Python hexstring-list-str之间的转换方法
2019/06/12 Python
Python Web版语音合成实例详解
2019/07/16 Python
Python创建临时文件和文件夹
2020/08/05 Python
HTML5新特性之用SVG绘制微信logo
2016/02/03 HTML / CSS
StubHub意大利:购买和出售全球演唱会和体育赛事门票
2017/11/21 全球购物
Kipling意大利官网:世界著名的时尚休闲包袋品牌
2019/06/05 全球购物
关于空气污染危害的感想
2015/08/11 职场文书
CentOS7和8下安装Maven3.8.4
2022/04/07 Servers
阿里云k8s服务升级时502错误 springboot项目应用
2022/04/09 Servers