type
status
date
slug
summary
tags
category
icon
password
今天介绍一下在使用webpack构建的项目,出现ChunkLoadError:Loading chunk x failed.报错时的一种解决方案

这个报错并不是资源请求失败,控制台并没有出现Network Erro这种请求失败的问题,而是资源模块挂载失败,可能是客户缓存了错误的资源导致。
这个报错是从webpack内部抛出的,代码位置是
这个文件是
webpack内部加载 chunk 资源的时候,判断资源是否正常加载,整体机制是webpack入口文件维护一份chunk资源的path以及其对应的资源号的列表(这个资源号也会编码在对应 chunk中)
- 遍历资源列表逐一加载,每次加载都会在页面中手动插入一段script脚本,
src赋值为资源地址,并挂载load和error两个事件的回调函数
- chunk脚本内部的入口会执行一段代码,访问
window中的全局变量,并将当前chunk中写死的模块号存入全局变量
- onload 会校验当前资源的模块号是否存在与全局的缓存中,存在则判定chunk加载成功,否则加载失败,抛出异常
下面这段代码用于抛出异常,异常的message由下面这段代码拼接:
注意其中的
errorType 字段,这个字段的取值有两种情况,如果 event.type === 'load' 则 errorType = 'missing', 否则就赋值为 event.type。所以如果错误中出现了
missing 的字样,就说明 event.type='load',也就是这个脚本实际是已经被正常加载了,但是出于某种原因,他没有通过资源编号的检测。是什么原因呢?
这里我代入了自己的一些主观猜测,这个报错主要是为了上报模块加载中的异常情况,如果资源加载成功,但是资源编号检查失败,是不是说明这段
chunk 本身有问题呢?- chunk加载了, 但是没有正常执行
第一种情况,可能是chunk内部有异常
第二种情况,我理解为chunk对应的地址存在浏览器缓存,在客户网络波动时没有完全加载完成,结果这份不完整的资源被缓存了起来,后续一直在使用错误的内容,比如客户拿到的资源中的模块号错误。
有了这个想法我找了一个项目进行尝试,Chrome代理返回的脚本内容,修改第一行的模块号,刷新页面后再次点击地区就会出现missing错误, 完美复现!

所以最终的解决方案,就是找到异常的
chunk ,强制刷新客户的缓存- 粗糙的方案:直接拿到
chunk地址,写一段脚本放在html中让客户访问
url-cache-flush
CreateSun • Updated Dec 30, 2024
我提供了一个清除缓存的工具供客户使用,显示
“clear success!” 即表示缓存清除成功。其实源码非常简单,就是用原生的
fetch 方法对目标chunk对地址发起请求,请求头中声明 "Cache-Control": "no-cache" 即可。- 优雅的方案:在代码中捕获异常,并进行自动重试
这种方式可以考虑在比如动态加载的入口,比如import语句、React.lazy外部增加catch捕获异常并解析目标地址,具体的实现方式就不展示了。
有关类似的 webpack资源加载问题,欢迎您在github留言,我们一起交流