Webpack代码分割:ChunkLoadError语言 - 加载块X失败,但块存在



几天前我把Sentry集成到我的网站上,我注意到有时用户会在他们的控制台收到这个错误:

ChunkLoadError: Loading chunk <CHUNK_NAME> failed.
(error: <WEBSITE_PATH>/<CHUNK_NAME>-<CHUNK_HASH>.js)

所以我在网上调查了这个问题,发现了一些类似的情况,但与会话期间发布更新或缓存问题导致的丢失块有关。

这些情况和我的主要区别在于,失败的块实际上是可以从浏览器访问的,所以加载错误不依赖于块哈希的释放后刷新,但(我猜),从一些网络相关的问题。这个假设被以下数据所强化:大约90%的设备是移动设备.

最后,我来到了问题我应该以某种方式管理这个问题吗?G.如果失败,重新尝试块加载)或者干脆忽略它,让用户手动刷新?


2021.09.28编辑:

一个月后,这个问题仍然存在,但我没有收到任何用户的报告,我也一直在记录用户使用Hotjar的会话,但到目前为止还没有发现任何相关的问题。

我最近和Sentry support聊天,帮助我排除了网络相关的假设:

我们的React SDK默认没有离线缓存,当一个错误被捕获时,它将在那一点上发送。如果应用不能连接到Sentry发送事件,它将被丢弃,SDK将不再尝试发送它。

Rodolfo from Sentry

我可以确认这个问题是非常不寻常的,我与你分享另一个有趣的数据:自第一次发生以来,受影响的用户是在332.227个独立访问者中有882个(~ 0.26%),但我注意到90%的出现都来自iOS(游戏邦注:这并不是我一个月前注意到的一般移动设备),所以如果我计算iOS用户的比例(游戏邦注:128.444名用户中有794名(882名中的90%)),我们便会发现这一比例接近0.62%。

块是可访问的并不意味着用户的浏览器可以解析它。例如,如果用户的浏览器是旧的。但是数据块包含了新的语法。

Webpack通过json加载chunk。将<script>标签插入<head>。如果js块文件下载但无法解析。一个ChunkLoadError将被抛出

您可以按照以下步骤复制它。编写一个可选的链,不要编译它。确保它输出到一个块。

const obj = {};
obj.sub ??= {};

打开你的应用程序chrome 79或safari 13.0。完整的错误信息如下所示:

SyntaxError: Unexpected token '?'           // 13.js:2
MAX RELOADS REACHED                         // chunk-load-handler.js:24
ChunkLoadError: Loading chunk 13 failed.    // trackConsoleError.js:25
(missing: http://example.com/13.js)

这很可能发生,因为浏览器正在缓存应用程序的主HTML文件,如index.html服务于webpack包和manifest.

首先,我会确保你的web服务器发送正确的HTTP响应头,而不是缓存应用程序的index.html文件(让我们假设它被称为)。如果你使用的是NGINX,你可以像这样设置合适的头:

location ~* ^.+.html$ {
add_header Cache-Control "no-store max-age=0";
}

对于SPA来说,这个文件应该相对较小,所以只要你缓存应用程序需要的所有其他资产(如JS和CSS等),就可以不缓存这个文件。你应该在JS包上使用内容散列来支持缓存破坏。有了这个,访问你的网站应该总是包含最新版本的index.html和最新的资产,包括最新的webpack清单,它记录了块的名称。

如果你想处理Chunk Load Errors,你可以这样设置:

import { ErrorBoundary } from '@sentry/react'
const App = (children) => {
<ErrorBoundary
fallback={({ error, resetError }) => {
if (/ChunkLoadError/.test(error.name)) {
// If this happens during a release you can show a new version alert
return <NewVersionAlert />
// If you are certain the chunk is on your web server or CDN
// You can try reloading the page, but be careful of recursion
// In case the chunk really is not available
if (!localStorage.getItem('chunkErrorPageReloaded')) {
localStorage.setItem('chunkErrorPageReloaded', true)
window.location.reload()
}
}
return <ExceptionRedirect resetError={resetError} />
}}>
{children}
</ErrorBoundary>
}

如果你决定重新加载页面,我会提前给用户一个消息。

相关内容

最新更新