通常情况下我们的 WebApp 是有我们的自身代码和第三方库组成的,我们自身的代码是会常常变动的,而第三方库除非有较大的版本升级,不然是不会变的,所以第三方库和我们的代码需要分开打包,我们可以给第三方库设置一个较长的强缓存时间,这样就不会频繁请求第三方库的代码了。

那么如何提取第三方库呢?在 webpack4.x 中, SplitChunksPlugin 插件取代了 CommonsChunkPlugin 插件来进行公共模块抽取,我们可以对SplitChunksPlugin 进行配置进行 拆包 操作。

SplitChunksPlugin配置示意如下:

optimization: {
splitChunks: {
chunks: "initial", // 代码块类型 必须三选一: "initial"(初始化) | "all"(默认就是all) | "async"(动态加载)
minSize: 0, // 最小尺寸,默认0
minChunks: 1, // 最小 chunk ,默认1
maxAsyncRequests: 1, // 最大异步请求数, 默认1
maxInitialRequests: 1, // 最大初始化请求书,默认1
name: () => {}, // 名称,此选项课接收 function
cacheGroups: { // 缓存组会继承splitChunks的配置,但是test、priorty和reuseExistingChunk只能用于配置缓存组。
priority: "0", // 缓存组优先级,即权重 false | object |
vendor: { // key 为entry中定义的 入口名称
chunks: "initial", // 必须三选一: "initial"(初始化) | "all" | "async"(默认就是异步)
test: /react|lodash/, // 正则规则验证,如果符合就提取 chunk
name: "vendor", // 要缓存的 分隔出来的 chunk 名称
minSize: 0,
minChunks: 1,
enforce: true,
reuseExistingChunk: true // 可设置是否重用已用chunk 不再创建新的chunk
}
}
}
} 复制代码

SplitChunksPlugin 的配置项很多,可以先去官网了解如何配置,我们现在只简单列举了一下配置元素。

如果我们想抽取第三方库可以这样简单配置

   splitChunks: {
chunks: 'all', // initial、async和all
minSize: 30000, // 形成一个新代码块最小的体积
maxAsyncRequests: 5, // 按需加载时候最大的并行请求数
maxInitialRequests: 3, // 最大初始化请求数
automaticNameDelimiter: '~', // 打包分割符
name: true,
cacheGroups: {
vendor: {
name: "vendor",
test: /[\\/]node_modules[\\/]/, //打包第三方库
chunks: "all",
priority: 10 // 优先级
},
common: { // 打包其余的的公共代码
minChunks: 2, // 引入两次及以上被打包
name: 'common', // 分离包的名字
chunks: 'all',
priority: 5
},
}
}, 复制代码

这样似乎大功告成了?并没有,我们的配置有很大的问题:

  1. 我们粗暴得将第三方库一起打包可行吗? 当然是有问题的,因为将第三方库一块打包,只要有一个库我们升级或者引入一个新库,这个 chunk 就会变动,那么这个chunk 的变动性会很高,并不适合长期缓存,还有一点,我们要提高首页加载速度,第一要务是减少首页加载依赖的代码量,请问像 react vue reudx 这种整个应用的基础库我们是首页必须要依赖的之外,像 d3.js three.js这种特定页面才会出现的特殊库是没必要在首屏加载的,所以我们需要将应用基础库和特定依赖的库进行分离。
  2. 当 chunk 在强缓存期,但是服务器代码已经变动了我们怎么通知客户端?上面我们的示意图已经看到了,当命中的资源在缓存期内,浏览器是直接读取缓存而不会向服务器确认的,如果这个时候服务器代码已经变动了,怎么办?这个时候我们不能将 index.html 缓存(反正webpack时代的 html 页面小到没有缓存的必要),需要每次引入 script 脚本的时候去服务器更新,并开启 hashchunk,它的作用是当 chunk 发生改变的时候会生成新的 hash 值,如果不变就不发生变动,这样当 index 加载后续 script资源时如果 hashchunk 没变就会命中缓存,如果改变了那么会重新去服务端加载新资源。

下图示意了如何将第三方库进行拆包,基础型的 react 等库与工具性的 lodash 和特定库 Echarts 进行拆分

      cacheGroups: {
reactBase: {
name: 'reactBase',
test: (module) => {
return /react|redux/.test(module.context);
},
chunks: 'initial',
priority: 10,
},
utilBase: {
name: 'utilBase',
test: (module) => {
return /rxjs|lodash/.test(module.context);
},
chunks: 'initial',
priority: 9,
},
uiBase: {
name: 'chartBase',
test: (module) => {
return /echarts/.test(module.context);
},
chunks: 'initial',
priority: 8,
},
commons: {
name: 'common',
chunks: 'initial',
priority: 2,
minChunks: 2,
},
}
复制代码

我们对 chunk 进行 hash 化,正如下图所示,我们变动 chunk2 相关的代码后,其它 chunk 都没有变化,只有 chunk2 的 hash 改变了

  output: {
filename: mode === 'production' ? '[name].[chunkhash:8].js' : '[name].js',
chunkFilename: mode === 'production' ? '[id].[chunkhash:8].chunk.js' : '[id].js',
path: getPath(config.outputPath)
}
复制代码

我们通过 http 缓存+webpack hash 缓存策略使得前端项目充分利用了缓存的优势,但是 webpack 之所以需要传说中的 webpack配置工程师 是有原因的,因为 webpack 本身是玄学,还是以上图为例,如果你 chunk2的相关代码去除了一个依赖或者引入了新的但是已经存在工程中依赖,会怎么样呢?

我们正常的期望是,只有 chunk2 发生变化了,但是事实上是大量不相干的 chunk 的 hash 发生了变动,这就导致我们缓存策略失效了,下图是变更后的 hash,我们用红圈圈起来的都是 hash 变动的,而事实上我们只变动了 chunk2 相关的代码,为什么会这样呢?

原因是 webpack 会给每个 chunk 搭上 id,这个 id 是自增的,比如 chunk 0 中的id 为 0,一旦我们引入新的依赖,chunk 的自增会被打乱,这个时候又因为 hashchunk 根据内容生成 hash,这就导致了 id 的变动致使 hashchunk 发生巨变,虽然代码内容根本没有变化。
这个问题我们需要额外引入一个插件HashedModuleIdsPlugin,他用非自增的方式进行 chunk id 的命名,可以解决这个问题,虽然 webpack 号称 0 配置了,但是这个常用功能没有内置,要等到下个版本了。

webpack hash缓存相关内容建议阅读此文章 作为拓展

作者:寻找海蓝96
链接:https://juejin.im/post/5d00820b5188255ee806a1c7
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Webpack 4 SplitChunksPlugin配置方案(转)的更多相关文章

  1. Webpack中SplitChunksPlugin 配置参数详解

    代码分割本身和 webpack 没有什么关系,但是由于使用 webpack 可以非常轻松地实现代码分割,所以提到代码分割首先就会想到使用 webopack 实现. 在 webpack 中是使用 Spl ...

  2. CSS预编译与PostCSS以及Webpack构建CSS综合方案

    CSS全称Cascading Style Sheets(层叠样式表),用来为HTML添加样式,本质上是一种标记类语言.CSS前期发展非常迅速,1994年哈肯·维姆·莱首次提出CSS,1996年12月W ...

  3. 自定义配置Webpack和Babel配置

    在使用ant-design-vue的包时样式是可以生效的但是如果我需要用到less文件时会报一个异常 当然这个异常其实很清晰的说明了什么问题看错误信息里面有issues地址,看来问题不止我们遇见了可以 ...

  4. 深入浅出 webpack 之基础配置篇

    前言 前端工程化经历过很多优秀的工具,例如 Grunt.Gulp.webpack.rollup 等等,每种工具都有自己适用的场景,而现今应用最为广泛的当属 webpack 打包了,因此学习好 webp ...

  5. Atitit.兼具兼容性和扩展性的配置方案attilax总结

    Atitit.兼具兼容性和扩展性的配置方案attilax总结 文件配置法1 Jdbc多数据源文件配置发1 Bat文件配置法1 改进的文件配置法(采用类似i18n技术) 推荐1 使用自动化pc_id的方 ...

  6. webpack + vuejs 基本配置(一)

    开始之前 本文包含以下技术,文中尽量给与详细的描述,并且附上参考链接,读者可以深入学习: 1.webpack2.Vue.js3.npm4.nodejs —- 这个就不给连接了,因为上面的连接都是在你实 ...

  7. webpack react基础配置一

    简单介绍webpack react基本配置,入门型: 环境配置: 依赖nodejs,官网下载最新版的nodejs:nodejs.org/en 安装完nodejs  npm便自动集成了,通过npm安装其 ...

  8. Spring MVC之视图解析器和URL-Pattern的配置方案

    上期讲解了第一入门案例之后接下来了解一下视图解析器与URL-Pattern的配置方案 先来说视图解析器,在上次博客文章中我们完成了入门案例,接下来我们就在上一个例子中完善一下体出视图解析器 <? ...

  9. Apache安全配置方案

    Apache安全配置方案 from:http://drops.wooyun.org/%e8%bf%90%e7%bb%b4%e5%ae%89%e5%85%a8/2727 apache的一些配置主要是通过 ...

随机推荐

  1. 大数据调度工具oozie详细介绍

    背景 之前项目中的sqoop等离线数据迁移job都是利用shell脚本通过crontab进行定时执行,这样实现的话比较简单,但是随着多个job复杂度的提升,无论是协调工作还是任务监控都变得麻烦,我们选 ...

  2. Spring AOP 知识点入门

    一.基本知识点 1.AOP概念 AOP(Aspect-Oriented Programming), 即 面向切面编程, 它与 OOP( Object-Oriented Programming, 面向对 ...

  3. 30、Python程序中的线程操作(oncurrent模块)

    进程是cpu资源分配的最小单元,一个进程中可以有多个线程. 线程是cpu计算的最小单元. 对于Python来说他的进程和线程和其他语言有差异,是有GIL锁. GIL锁 GIL锁保证一个进程中同一时刻只 ...

  4. Xml与Map之间的相互转换

    一.(单层)xml转换为map /** * XML格式字符串转换为Map * * @param xml XML字符串 * @return XML数据转换后的Map * @throws Exceptio ...

  5. linux命令之------rm命令

    rm命令 1)    作用:用于删除一个文件或者目录: 2)    -i:删除前逐一询问确认: 3)    -f:即使原档案属性设为只读,亦直接删除,无需逐一确认: 4)-r:将目录及以下之档案亦逐一 ...

  6. 关于finalize()

    finalize()是Object中的方法,当垃圾回收器将要回收对象所占内存之前被调用,即当一个对象被虚拟机宣告死亡时会先调用它finalize()方法,让此对象处理它生前的最后事情(这个对象可以趁这 ...

  7. gitlab 上传代码

    #生成公钥ssh-keygen -t ed25519 -C "xxx@tianwang.com"#拷贝公钥pbcopy < ~/.ssh/id_ed25519.pub 在网页 ...

  8. KD-Tree总结

    KD-Tree总结 问题引入 平面上有\(n\)个点,\(q\)组询问,每一次查询距离\((x,y)\)最近的点对,强制在线. 问题解决 暴力 显然我们可以直接枚举点然后算距离取\(min\),这样子 ...

  9. Java常见集合的默认大小及扩容机制

    在面试后台开发的过程中,集合是面试的热话题,不仅要知道各集合的区别用法,还要知道集合的扩容机制,今天我们就来谈下ArrayList 和 HashMap的默认大小以及扩容机制. 在 Java 7 中,查 ...

  10. 记一次cpu指标异常的跟踪排查

    问题描述: 最近在测试环境的服务器上,无意中发现cpu持续飙高.最高的时候达到了200%经过反复重启无效之后,决定挖掘深层次的原因 通过top命令打印出消耗cpu的pid,如图 通过ps -mp 24 ...