技术咨询、项目合作、广告投放、简历咨询、技术文档下载 点击这里 联系博主

# 记一次 React.lazy 加载页面导致 chunk load error 问题

你是否 使用了 React.lazy 做异步加载,并在部署了代码之后 发现存在 ChunkLoadError的问题; 如果是 可以继续查看一下当前文章

首先了解一下 React.lazy (opens new window) 如何使用

import React, { Suspense } from 'react';

const App = React.lazy(() => import('./App'));

function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <App />
      </Suspense>
    </div>
  );
}

那么 什么情况回导致如上的代码 加载失败,导致 chunk load error 呢?

# 导致 chunk load error 的原因

前置知识

  1. 异步组件,资源并不会一次性加载,而是执行到某块才会加载
  2. 在webpack 中我们打包资源通常会使用 contenthash/hash/chunk-hash, 重新打包发布后 hash 值不一样

根本原因是:打包之后hash 值变化,之前页面无法找到老的chunk 导致页面加载失败

举个例子:

  1. 现在假设您的代码发布线上,用户加载了您的主应用程序app.js

  2. 他们点击一个按钮来查看他们的个人信息。这是一个单独的代码块chunk-1a.min.js

if

    如果从用户加载应用程序后没有发生任何变化,代码块将加载;用户也可以正常使用。

else 

    如果在加载应用程序和 查看个人信息之间,部署了新 代码。
  1. 如果新的个人信息模块 chunk 为 chunk-1b.min.js。很有可能,您的生产环境将创建一个全新的构建,旧的块已经消失,新的已经准备就绪。

  2. 此时用户已经加载了旧版本的代码(html),它会寻找旧的 chunk chunk-1a.min.js 此时用户就会发送 load chunk error

# 如何修复 chunk load error

我们发现 出现 chunk load error的主要原因是无法找到 新的资源;所以一种可行的解决方案是 在导入失败时,引导用户刷新页面;

const lazyRetry = function(componentImport, name) {
    return new Promise((resolve, reject) => {
        // 检查是否已经刷新过了
        const hasRefreshed = JSON.parse(
            window.sessionStorage.getItem(`${name}-retry-lazy-refreshed`) || 'false'
        );
        // 动态导入组件
        componentImport().then((component) => {
            window.sessionStorage.setItem(`${name}-retry-lazy-refreshed`, 'false'); 
            resolve(component);
        }).catch((error) => {
            if (!hasRefreshed) { // 没有刷新过,需要刷新页面刷新
                window.sessionStorage.setItem(`${name}-retry-lazy-refreshed`, 'true'); 
                return window.location.reload(); // 
            }
            reject(error); 
        });
    });
}

// 将原本的  const App = React.lazy(() => import('./App')); 替换成如下即可
const App = React.lazy(() => lazyRetry(() => import(/* webpackChunkName: "main-app" */ './App'), "main-app"));


【未经作者允许禁止转载】 Last Updated: 2/4/2024, 6:06:40 AM