分享好友 最新动态首页 最新动态分类 切换频道
深入理解webpack的chunkId对线上缓存的思考
2024-12-29 21:31

想必经常使用基于webpack打包工具的框架的同学们,无论是使用React还是Vue在性能优化上使用最多的应该是分包策略(按需加载)。按需加载的方式使我们的每一个bundle变的更小,在每一个单页中只需要引入当前页所使用到的JavaScript代码,从而提高了代码的加载速度。但是,由于webpack目前版本自身的原因分包策略虽然可以提高我们的加载速度,然而在线上缓存方面却给了我们极大的破坏(webpack5中解决了这个问题)。

深入理解webpack的chunkId对线上缓存的思考

本文主要通过以下四个方面,来深入剖析chunkId:

  • chunkId是怎么生成的?
  • chunkId是怎么破坏线上缓存的?
  • 解决chunkId对破坏缓存的方法
  • 远观未来,webpack5完美解决

webpack是一个基于模块化的打包工具,其总体打包流程可分为:

  1. 初始化阶段
  2. 编译阶段
  3. 输出阶段

初始化阶段

webpack初始化阶段主要在webpack.js中完成,有以下方面:

  • webpack-cli启动,获取webpack.config.js配置及合并shell参数
  • 根据cli得到的配置合并默认配置
  • 创建compiler实例
  • 遍历配置中的plugins加载第三方插件
  • 初始化默认插件

编译阶段

初始化完成之后,cli得到compiler实例,执行compiler.run()开始编译,编译的过程主要分为以下步骤:

  • 分析entry,逐一遍历
  • 确定依赖模块,递归解析
  • 分包策略确定每一个chunk所包含的module,合并module生成chunk。
  • 确定模块资源
  • 根据chunk的entry的不同,确定输出template模板。

输出阶段

  • 输出文件

上面简单了解一下打包流程,当然最主要的目的不是为了了解打包流程,而是其中的一个点:chunk是怎么生成的

从编译阶段中可以看出,chunk是由多个module合并生成的,每一个chunk生成的时候都会有一个对应的chunkId,chunkId的生成策略是本节讨论的重点。

chunkId的生成策略可以在官网中找到,主要有五种规则:

  1. false:不适用任何算法,通过插件提供自定义算法。
  2. natural:自然数ID
  3. named:使用name值作为Id,可读性高。
  4. size:数字ID,依据最小的初始下载大小。
  5. total-size:数字ID,依据最小的总下载大小。

不同的生成规则所打包出来的chunkId是不同的。但是,其实内部生成方式是一样的,不同的规则只是对chunks中的chunk排序规则不同(说的什么玩意,什么一会相同,一会不同的)。不要着急,接下来就来看一下这东西到底是怎么生成的。

我们都知道webpack的optimization中有个chunkIds的配置,上面五种值,就是它的可选值。在开发环境下默认值为named,在生产环境下默认值为size。

在webpack初始化阶段会挂载内部插件,我们直接定位到这个文件的第437行。


上面代码中可以看到,在初始化阶段不同的chunkIds的值会加载不同的插件,并且进入这个插件内部你会发现他们都是挂载到这个钩子上。那么疑问来了,这个钩子是在什么时机执行的呢?定位到``compilation.js`的第1334行会得到答案。


在执行流程中可以看出,chunkId在生成前确定生成规则。可能你的疑问又来了,它是怎么根据chunkId的值的不同生成规则呢?其实所有的chunk都存放在一个数组里面(也就是chunks),在中根据规则的不同对chunk进行相应的排序,然后再统一的对进行赋值。眼见为实,我们先来看一下applyChunkIds中是怎么赋值的,定位到compilation.js中的1754行。


这生成过程中判断chunk.id是否为null,如果为null,对id赋值nextFreeChunkId。没错,无论是什么生成规则,都是这样赋值的。明白了所有的生成规则都是使用相同的赋值规则之后,我们现在的疑问应该就是每个规则中是怎么对chunks进行排序的?接下来就来看一下每个规则是怎么做的。

在中我们可以知道,chunkIds值为natural的时候,挂载的是这个插件。


首先,在每一个chunk中都有一个这个属性,它是一个,里面存放的是所有合并当前的module,每个module的id属性表示当前module的。主要做的事就是根据moduleId来最为排序规则进行排序。

named的生成规则比较简单,根据chunk的name取值


named与其他方式的区别在于,named不是在中对chunkId操作,而是在beforeChunkIds阶段。所做的事是遍历所有的chunk,判断chunk的id值是否为null,如果为null,取到chunk的name值赋予id。

当执行的时候,由于当前的id值已经不是null了,所以跳过赋值规则,直接使用已存在的值。

size和total-size规则由于调用的是相同的插件,只是参数的不同,所以我们就一起看一下它是怎么做的。打开文件。

size和total-size调用插件的区别:

  1. size规则:prioritiseInitial为true。
  2. total-size规则:prioritiseInitial为false。

OccurrenceChunkOrderPlugin通过prioritiseInitial区分是size还是total-size:

  • prioritiseInitial为true:根据父模块的数量排序,如果数量相同走total-size的逻辑。
  • prioritiseInitial为false:首先根据chunk的groups的数量排序,如果数量相同,根据chunk所在的索引排序。
  1. 首先我们会发现除了named之外的规则都是生成的number值,并且只是在生成chunkId前,对chunks以不同的规则进行排序。
  2. 通过named规则,我们可以发现,如果在beforeChunkIds中给chunkId赋值,那么就会阻截默认的规则。

说到破坏,我们心中可能又会有疑问,这东西怎么会破坏线上缓存呢?我们来模拟一个场景。

想必业务思想很好的你,有时候也会让业务的快速变更搞的非常烦恼,假设一个blog项目三个功能模块:文章列表页、文章标签页、关于页,并且三个功能模块都是异步的。我们来简写一下代码。

首先入口文件为index.js,三个功能模块代码为articleList.js、articleTag.js、about.js。


在index.js中异步引入这三个功能模块。


我们使用生产环境打包一下,得到dist目录中的文件如下:

很完美,打包成功,结果也肯定和我们想的一样。

假如有一天,需求变了,关于我们页不想要了,让它暂时不存在项目里面了(为了方便文件的diff,我们先把当前的代码做一个备份),我们可以先把About的代码在index.js中的代码注释。


注释之后,重新打包。重新生成的文件和备份的如下

可以你会说,这不小意思吗?我有webpack的魔法注释,不让文件名变不就得了。(此时作者只能呵呵一笑)我们来验证一下。

我们来把index中引入的三个模块都加上魔法注释:


打包结果如下

  1. 按需加载可以使单个js文件的代码量更小、加载更快,但是带来优化的同时也对缓存产生了极大的伤害。
  2. 缓存是性能优化中极为重要的部分,罪魁祸首在chunkId,所以必须盘它。

相信上述问题,早已被社区的同学们发现,笔者在也曾找了一会插件,但都没有如愿,心里不服,干脆自己写一个。

webpack-fixed-chunk-id-plugin 这个插件已经被笔者发布到npm,代码极简,可能会存在不足,还望社区大佬多多提建议,共同成长。

根据上文我们可以得出,万物的罪魁祸首是chunkId,所以必须要固定它,才能让文件内容不会变。那如何固定呢?

第一点:根据上文第一部分分析chunkId生成原理的时候,我们从named这个规则中得出只要在,这个地方给chunkId一个值,在阶段就不会对chunkId执行定义的规则。

第二点:上一点得出在webpack什么阶段来控制chunkId,那么这点就应该讨论控制chunkId要基于什么来控制? 第一个想到的肯定是内容,基于内容来控制chunkId,当内容变chunkId变、内容不变chunkId不变。

基于上面两点,插件代码如下:


通过挂载到beforeChunkIds钩子上,拿到所有的chunk,遍历每一个chunk得到所有合并当前chunk的module的内容,使用node的crypto加密模块,对内容计算hash值,设置。下面我们来测试一下,这个插件好不好用。





  1. 根据打包问题,确定事故发生地点---chunkId。
  2. 根据事故发生时机,找出阻截事故发生方案---beforeChunkIds。
  3. 定制可行方案---基于module内容来生成唯一hash。

chunkId事故问题可谓webpack自身留下的坑,chunkId方便了开发者,同样chunkId也对我们造成了极大的破坏,正所谓:成也chunkId、败也chunkId。

webpack4中遗留的问题,在还未现世的webpack5中得到了完美的解决。

接下来开始尝鲜webpack5。由于webpack5还未发版,我们可以通过一些方法来使用它。


把webpack4中的src下的代码拷贝到webpack5中打包,结果如下:

我们来按照之前的方式验证一下,把about模块注释,并使用Beyond Compare比较一下。

虽然webpack5可以执行以上操作,但是由于目前还未发布,以cli的配合并不完善。目前的版本,只要写webpack.config.js使用cli启动就会报错,如果要使用配置文件的话就只能使用node来启动webpack。

并且如果要使用webpack5完美的chunkId,还需要在webpack配置文件中配置一下内容:



目前的webpack5已经有了很多优秀的特性,包括代码也变的更加简介,总之,拥抱webpack5吧。

最新文章
ai智能助手 ai智能助手怎么无法打开?
1.WPS演示中右下角的助手功能暂时不支持关闭,该功能不点击使用就不会触发启动。2.如需关闭WPS文字中的智能识别目录功能,可点击左上角“文件”—“选项”—“视图”,取消勾选“打开文件,展示智能识别目录”即可。智能AI助手免费在当今数
17173.com网络游戏:《传 奇3》专区
月魔蜘蛛被赤月恶魔的魔力变成畸形的蜘蛛,有着蜘蛛的身体和蝙蝠的翅膀,可以在飞行中攻击。身体成大球状,有很多圆形突起物,从这里喷出致命的毒液,瘫痪敌人。独眼蜘蛛同样也是被赤月恶魔改造过的怪物。虽然不大,但它有坚硬强壮的身体和
DeepL拍照翻译 24.12
deepl,实用、强大的翻译应用。领先的NMT翻译引擎(神经网络机器翻译),让多语言互译更加可靠有保证。专业的拍照翻译、图片翻译、语音对话翻译软件。支持几十种国际语言互译。是您外语学习、旅游出行的必备工具。华军软件园提供DeepL拍照
ASPCMS 开源企业网站内容管理系统 UTF8 v2.7.7
ASPCMS是由上谷网络开发的全新内核的开源企业建站系统,能够胜任企业多种建站需求,并且支持模版自定义、支持扩展插件等等,能够在短时间内完成企业建站。 本版为直接使用版 , 下载后上传即可使用 , 详细请查看下载源码中文档说明。功能
Discuz论坛SEO优化技巧分享
Discuz论坛一直以来是国内最受欢迎的论坛软件之一,它功能强大、灵活性高,而且支持SEO优化,有助于提高论坛的搜索引擎可见性和流量。本文将分享一些Discuz论坛SEO优化的技巧,包括具体的代码示例,帮助网站管理员更好地优化论坛以提升排名
AI控制工业机器人入门教程
简介 AI控制的工业机器人正在改变现代制造业的面貌。与传统的编程控制不同,AI使机器人能够通过感知环境、自主决策和学习不断优化自身的操作。这篇教程将介绍实现AI控制工业机器人的必要知识和技能,帮助读者从基础开始构建起A
AI画图无审核"引发热议:创作者们的自由与伦理的巨大碰撞,震惊业界的影响正在显现!
  最新消息:某知名艺术平台近日宣布将不再对用户上传的AI生成作品进行审核,这一决定引发了广泛关注和热议。创作者们在享受自由表达的同时,也面临着伦理与法律的巨大挑战。  随着技术的发展,AI工具为艺术创作带来了前所未有的便利。
360 企业安全云
随着云计算、大数据、人工智能技术的飞速发展,当前大型企业的数字化转型已经走上了快车道,在充足的资金、技术、人才支持下,各类企业级软件和云服务让企业生产力大幅提升,实现了降本增效和高质量发展。各级政府机构、组织、企业单位等也
360借条催债合法吗
360借条催债合法吗?一、 小编导语近年来,随着互联网金融的快速发展,网络借贷平台层出不穷。360借条作为其中一个较为知名的平台,其便捷的借贷流程吸引了众多用户。伴随着借贷便利性的同时也存在着一些风险,其中催债方式是否合法合规成
相关文章
推荐文章
发表评论
0评