一步一步的了解webpack4的splitChunk插件(小结)


Posted in Javascript onSeptember 17, 2018

初衷

webpack4出了两个月,发现大家包括我对splitChunk的使用都还是在摸索阶段。我也看了挺多别人的配置demo,都觉得不太满意或者没得到太好的解惑,issue 下面的问题也没什么人回复,只能自己操作了,顺便记录下来,如果大家有更好的,欢迎评论区留下地址。

常用参数

  • minSize(默认是30000):形成一个新代码块最小的体积
  • minChunks(默认是1):在分割之前,这个代码块最小应该被引用的次数(译注:保证代码块复用性,默认配置的策略是不需要多次引用也可以被分割)
  • maxInitialRequests(默认是3):一个入口最大的并行请求数
  • maxAsyncRequests(默认是5):按需加载时候最大的并行请求数。
  • chunks (默认是async) :initial、async和all
  • test: 用于控制哪些模块被这个缓存组匹配到。原封不动传递出去的话,它默认会选择所有的模块。可以传递的值类型:RegExp、String和Function
  • name(打包的chunks的名字):字符串或者函数(函数可以根据条件自定义名字)
  • priority :缓存组打包的先后优先级。

如果你对这些配置还是不熟悉的话,一拉到底,看看文档

正文

先总览一下所有配置,后续会根据demo跑一遍常见的需求。

optimization: {
 splitChunks: {
  chunks: "async", // 必须三选一: "initial" | "all"(推荐) | "async" (默认就是async)
  minSize: 30000, // 最小尺寸,30000
  minChunks: 1, // 最小 chunk ,默认1
  maxAsyncRequests: 5, // 最大异步请求数, 默认5
  maxInitialRequests : 3, // 最大初始化请求书,默认3
  automaticNameDelimiter: '~',// 打包分隔符
  name: function(){}, // 打包后的名称,此选项可接收 function
  cacheGroups:{ // 这里开始设置缓存的 chunks
   priority: 0, // 缓存组优先级
   vendor: { // key 为entry中定义的 入口名称
    chunks: "initial", // 必须三选一: "initial" | "all" | "async"(默认就是async) 
    test: /react|lodash/, // 正则规则验证,如果符合就提取 chunk
    name: "vendor", // 要缓存的 分隔出来的 chunk 名称 
    minSize: 30000,
    minChunks: 1,
    enforce: true,
    maxAsyncRequests: 5, // 最大异步请求数, 默认1
    maxInitialRequests : 3, // 最大初始化请求书,默认1
    reuseExistingChunk: true // 可设置是否重用该chunk
   }
  }
 }
 },

接下来看看第一个例子

entry: {
		pageA: "./pageA", // 引用utility1.js utility2.js
		pageB: "./pageB", // 引用utility2.js utility3.js
		pageC: "./pageC" // 引用utility2.js utility3.js
	},
	
	optimization: {
		splitChunks: {
			cacheGroups: {
				commons: {
					chunks: "initial",
					minChunks: 2,
					maxInitialRequests: 5, // The default limit is too small to showcase the effect
					minSize: 0 // This is example is too small to create commons chunks
				}
			}
		}
	},

结果如图,一切都很正常 commons~pageA~pageB~pageC.js 文件就是utility2.js commons~pageB~pageC.js,根据上述代码,这里的utility2被引用了三次,首先就被抽离了commons~pageA~pageB~pageC.js,然后utility3被引用了两次就放到了commons~pageB~pageC.js,最后只剩下被引用一次的utility1.js,就直接放到了pageA.js里面,如果这里的utility1.js的也是两次,他还是会新建一个chunk放进去,而不是合并到commons~pageB~pageC.js,除非同入口引用才会合并。

mpageA.js pageB.js pageC.js

一步一步的了解webpack4的splitChunk插件(小结)

这里有个地方是需要优化一下的,就是pageA.js pageB.js pageC.js的代码不多,但是打出来的包很大,肯定是一些webpack的运行文件,直接加上runtimeChunk

runtimeChunk: "single"
 // 等价于
 runtimeChunk: {
  name: "manifest"
 }

现在就好了

一步一步的了解webpack4的splitChunk插件(小结)

引用第三方模块 pageA引用vue.js pageB引用react react-dom

vendor: {
		test: /node_modules/,
		chunks: "initial",
		name: "vendor",
		priority: 10,
		enforce: true
	}

但是,这样子的话,会把pageA pageB pageC所有的库都打包到一起vendor.js

一步一步的了解webpack4的splitChunk插件(小结)

假如我想拆分这个vendor.js为pageA-vendor.js pageB-vendor.js怎么办,我试了很久,试出一个最简单的办法,去掉手动的vendor,让插件自动处理。

splitChunks: {
  chunks: "all",
  cacheGroups: {
				commons: {
					chunks: "initial",
					minChunks: 2,
					maxInitialRequests: 5, // The default limit is too small to showcase the effect
					minSize: 0 // This is example is too small to create commons chunks
				}
			}
		},

一步一步的了解webpack4的splitChunk插件(小结)

后来,我把webpack mode改成production后,发现不管用了,同样的配置,在生产模式下,打包出来的东西有点匪夷所思,vendor-pageB.js被合并到了pageB.js里面了。

一步一步的了解webpack4的splitChunk插件(小结)

后来我折腾了好久也分析不出来为什么,自己折腾出来一种方式,还是老子手动来吧,自动化一边去

commons: {
   chunks: "initial",
   minChunks: 2,
   maxInitialRequests: 5, // The default limit is too small to showcase the effect
   minSize: 0 // This is example is too small to create commons chunks
	},
  'vendor-pageA': {
   test: /vue/, // 直接使用 test 来做路径匹配
   chunks: "initial",
   name: "vendor-pageA",
   enforce: true,
  },
  'vendor-pageB': {
   test: /react/, // 直接使用 test 来做路径匹配
   chunks: "initial",
   name: "vendor-pageB",
   enforce: true,
  },

成功打包出来了自己想要的东西。

一步一步的了解webpack4的splitChunk插件(小结)

动态引入

动态引入大家应该都不陌生,就是大家所说的懒加载,直接在pageA和pageB页面里动态引入common-async.js,在这里我先说说,splitChunk应该是可以自动化处理类似commonChunk里的async,child等情况的。

import(/* webpackChunkName: "common-async.js" */"./common-async").then(common => {
 console.log(common);
})

还不错,成功打包出来了

一步一步的了解webpack4的splitChunk插件(小结)

这时候再试试,在这个common-async.js里面在引入共同的代码f.js,看看会不会重复打包

一步一步的了解webpack4的splitChunk插件(小结)

f.js成功的被抽离出来了,其他文件也没有被重复打包,挺好的。

一步一步的了解webpack4的splitChunk插件(小结)

注意的地方

  • cacheGroups 会继承和覆盖splitChunks的配置项,但是test、priorty和reuseExistingChunk只能用于配置缓存组。。
  • cacheGroups 里的每一项最好都要加上chunks参数,不然可能打包不出来你想要的东西。
  • minSize 默认是30KB(注意这个体积是压缩之前的)在小于30kb的情况下一定要设置一个值,否则也可能打包不出来你想要的东西,而且这东西要加在cacheGroups里面。
  • priority 在某些情况下,还是挺有用的,可以设置打包chunks的优先级。

上面的例子里面配置了一个commons,这里的name可以自己设置,也可以不设置,我是没设置的,你可以试试设置了是什么样子的,然后你就会明白这个name其实在某些情况下还是不设置的比较好。

commons: {
   	chunks: "initial",
		minChunks: 2,
		maxInitialRequests: 5, // The default limit is too small to showcase the effect
		minSize: 0 ,
		name: "commons"
  },

源码

代码分割

代码懒加载

参考文章

webpack文档
官方demo

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

Javascript 相关文章推荐
JavaScript表达式:URL 协议介绍
Mar 10 Javascript
你可能不知道的JavaScript的new Function()方法
Apr 17 Javascript
Javascript中innerHTML用法实例分析
Jan 12 Javascript
使用AngularJS实现可伸缩的页面切换的方法
Jun 19 Javascript
js实现n秒倒计时后才可以点击的效果
Dec 20 Javascript
vue+vuex+axio从后台获取数据存入vuex实现组件之间共享数据
Apr 22 Javascript
基于Require.js使用方法(总结)
Oct 26 Javascript
vue-cli3.0配置及使用注意事项详解
Sep 05 Javascript
layui type2 通过url给iframe子页面传值的例子
Sep 06 Javascript
JavaScript中0、空字符串、'0'是true还是false的知识点分享
Sep 16 Javascript
浅谈vue项目用到的mock数据接口的两种方式
Oct 09 Javascript
vue中选中多个选项并且改变选中的样式的实例代码
Sep 16 Javascript
React Router V4使用指南(精讲)
Sep 17 #Javascript
关于vue编译版本引入的问题的解决
Sep 17 #Javascript
理顺8个版本vue的区别(小结)
Sep 17 #Javascript
vue.js编译时给生成的文件增加版本号
Sep 17 #Javascript
详解关于Vue版本不匹配问题(Vue packages version mismatch)
Sep 17 #Javascript
详解如何解决Vue和vue-template-compiler版本之间的问题
Sep 17 #Javascript
微信小程序中this.data与this.setData的区别详解
Sep 17 #Javascript
You might like
php检测用户是否用手机(Mobile)访问网站的类
2014/01/09 PHP
php简单实现多维数组排序的方法
2016/09/30 PHP
PHP实现分布式memcache设置web集群session同步的方法
2018/04/10 PHP
PHP实现的装箱算法示例
2018/06/23 PHP
PHP实现简易图形计算器
2020/08/28 PHP
基于SVG的web页面图形绘制API介绍及编程演示
2013/06/28 Javascript
Dojo Javascript 编程规范 规范自己的JavaScript书写
2014/10/26 Javascript
返回函数的JavaScript函数
2016/06/14 Javascript
AngularJS入门示例之Hello World详解
2017/01/04 Javascript
nodejs使用express创建一个简单web应用
2017/03/31 NodeJs
Vue中的ref作用详解(实现DOM的联动操作)
2017/08/21 Javascript
JavaScript面向对象精要(上部)
2017/09/12 Javascript
Puppeteer环境搭建的详细步骤
2018/09/21 Javascript
利用Python的装饰器解决Bottle框架中用户验证问题
2015/04/24 Python
Python中asyncore异步模块的用法及实现httpclient的实例
2016/06/28 Python
Python 爬虫学习笔记之多线程爬虫
2016/09/21 Python
Python 利用内置set函数对字符串和列表进行去重的方法
2018/06/29 Python
解决Python3下map函数的显示问题
2019/12/04 Python
详解Pycharm出现out of memory的终极解决方法
2020/03/03 Python
python实现贪吃蛇游戏源码
2020/03/21 Python
海外淘书首选:AbeBooks
2017/07/31 全球购物
SQL中where和having的区别
2012/06/17 面试题
关于是否需要写商业计划书
2014/02/07 职场文书
户外婚礼策划方案
2014/02/08 职场文书
路政管理毕业自荐书范文
2014/02/10 职场文书
个人承诺书
2014/03/26 职场文书
市场营销毕业求职信
2014/08/07 职场文书
2014年国庆节活动总结
2014/08/26 职场文书
2014乡党委副书记党建工作汇报材料
2014/11/02 职场文书
先进教师个人总结
2015/02/11 职场文书
考研导师推荐信范文
2015/03/27 职场文书
幸福终点站观后感
2015/06/04 职场文书
MySQL Router实现MySQL的读写分离的方法
2021/05/27 MySQL
mybatis中注解与xml配置的对应关系和对比分析
2021/08/04 Java/Android
关于MySQL中的 like操作符详情
2021/11/17 MySQL
Python OpenCV实现图像模板匹配详解
2022/04/07 Python