Loading chunk {n} failed 的解决方法

背景:

  • 前端代码更改后,每次发布到测试环境,用户的页面如果不刷新,会读取缓存,导致页面白掉!
  • 本地没有过,都是打包到服务器上才有

error info

Uncaught SyntaxError: Unexpected token '<'
Uncaught ChunkLoadError: Loading chunk 8 failed.
(missing: https://mispaceuat.mihoyo.com/static/js/8.98f2a71fc60af3a81dd1.js)
    at Function.i.e (https://mispaceuat.mihoyo.com/static/js/app.98f2a71fc60af3a81dd1.js?98f2a71fc60af3a81dd1:1:934)
    at https://mispaceuat.mihoyo.com/static/js/app.98f2a71fc60af3a81dd1.js?98f2a71fc60af3a81dd1:1:3105
    at https://mispaceuat.mihoyo.com/static/js/vendor.98f2a71fc60af3a81dd1.js?98f2a71fc60af3a81dd1:2:1229684
    at gl (https://mispaceuat.mihoyo.com/static/js/vendor.98f2a71fc60af3a81dd1.js?98f2a71fc60af3a81dd1:2:1229833)
    at sc (https://mispaceuat.mihoyo.com/static/js/vendor.98f2a71fc60af3a81dd1.js?98f2a71fc60af3a81dd1:2:1221601)
    at lc (https://mispaceuat.mihoyo.com/static/js/vendor.98f2a71fc60af3a81dd1.js?98f2a71fc60af3a81dd1:2:1221526)
    at $l (https://mispaceuat.mihoyo.com/static/js/vendor.98f2a71fc60af3a81dd1.js?98f2a71fc60af3a81dd1:2:1218556)
    at https://mispaceuat.mihoyo.com/static/js/vendor.98f2a71fc60af3a81dd1.js?98f2a71fc60af3a81dd1:2:1170263
    at e.unstable_runWithPriority (https://mispaceuat.mihoyo.com/static/js/vendor.98f2a71fc60af3a81dd1.js?98f2a71fc60af3a81dd1:2:1244959)
    at Ia (https://mispaceuat.mihoyo.com/static/js/vendor.98f2a71fc60af3a81dd1.js?98f2a71fc60af3a81dd1:2:1169972)

报错原因分析:

  • webpack 打包重命名了改动过的 css 和 js 文件,并删除了原有的文件
    • 场景1.用户正在浏览页面时你发包了,并且你启用了懒加载,用户的 html 文件中的 js 和 css 名称就和服务器上的不一致导致
    • 场景2.用户浏览器有 html 的缓存,访问了上一个版本发布的资源导致
  • webpack 进行 code spilt 之后某些 bundle 文件 lazy loading 失败
  • 其他原因:
    • 服务器打包时没有进行rm -f public/dist/*操作
    • 抓包:看自己的 chunk 文件内容是不是被篡改
    • 没有升级版本号导致的问题

关键

  • 刷新:会重新获取一遍 html 文档,chunk 对应信息也就刷新
    • 仅捕获到错误就刷新,很可能出现死循环,因为浏览器或者类似于Nginx缓存设置的原因,浏览器不一定每次刷新去获取新的index.html

解决方案

  • 方案1:结合重试次数和重试间隔来重试,用 location.reload 方法,相当于触发 F5 刷新页面
    • 缺点:reload 方法,相当于触发 F5 刷新页面,用户会察觉加载刷新
    • 捕获到了Loading chunk {n} failed的错误时,重新渲染目标页面,通过正则检测页面出错:用window.location.reload(true)刷新页面
// prompt user to confirm refresh
function forceRefresh(){
  // 设置只强制刷行一次页面
  if(location.href.indexOf('#reloaded')===-1){
    location.href = location.href + '#reloaded';
    window.location.reload(true);
    // window.location.reload();
  }else{
    alert('请手动刷新页面!');
  }
}
window.addEventListener('error',(e)=>{
  const pattern = /Loading chunk (\d)+ failed/g;
  const isChunkLoadFailed = error.message.match(pattern);
  // const isChunkLoadFailed =  /Loading chunk [\d]+ failed/.test(e.message)
  if (isChunkLoadFailed) forceRefresh()
  // const targetPath = router.history.pending.fullPath;
  // if (isChunkLoadFailed) router.replace(targetPath);
})
  • 方案2:构建的时候静态资源路径带上版本信息

    • 如路径中携带,如原来请求/static/js/balabal.[hash].js,现在/[version]/static/balabal.[hash].js
  • 方案3:让页面每次加载新数据而不是走缓存,React入口文件,加入;同时让后端帮忙修改Nginx,设置no-cache,让页面不要每次去读取缓存

<meta http-equiv="Cache-control" content="no-cache">
<meta http-equiv="Cache" content="no-cache">
  • 方案4:对比 test 和 uat 环境 config 文件配置

  • 方案5:尝试入口文件 client\index.tsx 处进行热更新

declare const module: any
if (process.env.NODE_ENV === 'development' && module.hot) {
module.hot.accept('./app', () => {
  location.reload()
})
}

拓展

react错误边界

网易开源库:https://github.com/x-orpheus/catch-react-error

GitHub讨论:https://github.com/nuxt/nuxt.js/issues/742

React.Lazy 的原理

lazyComponent is not a component but a function that returns a promise object. Inside of the promise that we return from componentLoader, we trigger the function (lazyComponent) and add handlers for promise resolve (.then) and reject(.catch). Since the successful resolution of promise is not a problem in our use case, we let React.lazy handle the resolved contents.
function componentLoader(lazyComponent) {
  return new Promise((resolve, reject) => {
    lazyComponent()
      .then(resolve)
      .catch((error) => {
        // let us retry after 1500 ms
        setTimeout(() => { // call componentLoader again!
          if (attemptsLeft === 1) {
            reject(error);
            return;
          }
          componentLoader(lazyComponent, attemptsLeft - 1).then(resolve, reject);
          // add one line to make it all work
        }, 1500);
      });
  });
}

封装retry方法

function retry(
  fn: () => Promise<{
    default: React.ComponentType<any>;
  }>,
  retriesLeft = 100,
  interval = 1000
) {
  return new Promise<{
    default: React.ComponentType<any>;
  }>((resolve, reject) => {
    fn()
      .then(resolve)
      .catch((error: any) => {
        setTimeout(() => {
          if (retriesLeft === 1) {
            reject(error);
            return;
          }
          retry(fn, retriesLeft - 1, interval).then(resolve, reject);
        }, interval);
      });
  });
}
component: lazy(() => retry(() => import("./pages/dashboard/Dashboard")))

交流


1、QQ群:可添加qq群共同进阶学习: 进军全栈工程师疑难解  群号:   856402057

2、公众号:公众号「进军全栈攻城狮」 ,对前端技术保持学习爱好者。我会经常分享自己所学所看的干货,在进阶的路上,共勉!通过公众号可加我vx拉群

 

### 解决 UmiJS 4.0 加载 Chunk 失败的问题 UmiJS 是一个可插拔的企业级 react 应用框架,在使用过程中可能会遇到加载 chunk 文件失败的情况。以下是针对此问题的分析和解决方案。 #### 可能的原因 1. **网络请求失败** 如果 `http://localhost:8080/remoteEntry.js` 的资源无法被正确加载,则可能是由于服务器未正常提供文件或者客户端未能成功发起请求[^1]。 2. **模块联邦配置错误** 在微前端场景下,如果 `app1` 和 `app2` 使用了 Webpack Module Federation 配置,而 `app1` 提供的远程入口 (`remoteEntry.js`) 路径设置有误或未正确暴露组件,则可能导致解析失败。 3. **动态导入机制问题** 类似于 `require('bundle-loader!./a.js')` 这样的动态加载方式可能存在问题,尤其是在异步加载时,Webpack 或者 UmiJS 对依赖关系处理不当会引发类似的错误[^2]。 4. **环境变量或缓存冲突** 某些情况下,浏览器端可能存在旧版本的 JS 缓存,或者服务端的静态资源配置不一致也会导致此类问题发生。 --- #### 解决方案 ##### 方法一:验证并修复路径配置 确认 `app1` 是否已通过正确的 URL 导出了其远程条目 (Remote Entry),即检查 `webpack.config.js` 中关于 Module Federation 插件的相关部分: ```javascript new ModuleFederationPlugin({ name: 'app1', filename: 'remoteEntry.js', // 确保此处与实际访问地址匹配 exposes: { './Header': './src/components/Header' // 曝光 Header 组件给其他应用调用 }, }); ``` 同时确保 `app2` 正确引入了来自 `app1` 的模块定义: ```javascript new ModuleFederationPlugin({ remotes: { app1: 'app1@http://localhost:8080/remoteEntry.js' } }) ``` 上述代码片段需严格遵循官方文档中的最佳实践来避免潜在的拼写错误或其他语法问题。 ##### 方法二:调整 Webpack 输出策略 对于生产环境中可能出现的跨域资源共享(CORS)限制或者其他性能瓶颈,可以尝试优化 Webpack 构建选项: - 设置公共路径(`publicPath`) - 启用长期缓存(long-term caching) 例如修改 Webpack 配置如下所示: ```javascript output: { publicPath: 'auto', // 自动检测当前运行环境下的基础路径 }, optimization: { splitChunks: { chunks: 'all' }, // 将第三方库单独打包成独立chunk } ``` 这一步骤有助于减少因路径映射不清而导致的加载失败风险。 ##### 方法三:清理缓存重新部署 强制清除本地以及远端的所有相关缓存数据后再执行完整的构建流程: ```bash rm -rf node_modules dist .cache && npm install && umi build --clean ``` 此外还需注意重启开发服务器以同步最新的改动效果。 ##### 方法四:增强网络层稳定性 考虑到偶尔发生的瞬态连接中断现象,适当增大 TCP 协议栈缓冲区大小能够提升大流量条件下的传输效率: ```shell sysctl -w net.core.rmem_default=4194304 sysctl -w net.core.rmem_max=4194304 sysctl -w net.core.wmem_default=4194304 sysctl -w net.core.wmem_max=4194304 ``` 尽管这些参数通常适用于数据库后台进程如 Oracle 数据库实例遭遇崩溃恢复期间内存分配不足的情形[^3],但对于高并发 web 请求同样具备一定的借鉴意义。 --- ### 总结 综上所述,解决 UmiJS 4.0 加载 chunk 失败的关键在于仔细排查各环节之间的交互逻辑是否存在偏差,并采取针对性措施逐一排除干扰因素直至恢复正常运作状态为止。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值