线上项目版本升级问题

项目场景

最近着手的react项目上有个需求,关于版本更新后,因为项目是按需加载的,前端页面点击菜单时会去拿对应菜单名称+哈希值的js文件,然后页面就会报Error:Loading chunk 10 failed.这一类的错误,会直接影响到正在使用平台的用户的体验。


原因分析

代码有更改后,webpack打包后的文件会生成新的哈希值后缀,但是项目入口页缓存的还是老哈希值,这就会导致已加载的项目依然会去加载老哈希值对应的文件,与此同时在服务器上,你的老哈希值文件已经被替换了,于是就会产生你拿不到对应文件的报错。

错误图片
类似于这种


解决方案

react

react我尝试了很多种方案,有些方案更改成本会很大,这边大家可以避坑

1.譬如有个兄弟说的,定位到webpack中报错这一行的源码,在源码下添加window.location.reload()即可,这种方式导致你需要fork一下你使用的webpack版本,自己修改源码后上传一个新的npm包,再修改一系列的依赖,确实可以实现重载需求,但是会踩很多坑(不推荐);
2. 想通过react自带的错误处理机制:v15版本使用unstable_handleError,16版本使用EerrorBoundary

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }
  
  v15版本---后续版本已废弃
  unstable_handleError(e) {
  	console.log(e)
  }

  v16版本---最新使用方法
  componentDidCatch(error, info) {
    // Display fallback UI
    this.setState({ hasError: true });
    // You can also log the error to an error reporting service
    logErrorToMyService(error, info);
  }

  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}


<ErrorBoundary>
  <MyWidget />
</ErrorBoundary>

很抱歉的告诉你,这一类的方法都监听不到,因为人家是资源加载失败,压根还没有进入到组件内,所以这连个方法也是不可行;还有一些提出的在路由中去监听的,我也尝试过,同样的理由,均以失败告终;
3. 最后就是只能妥协,使用浏览器的监听模式,通过webpack源码我发现它使用的是promise的方式抛出异常,那我们就去捕获未处理的promise异常,在入口页index.html使用unhandledrejection

   <!DOCTYPE html>
<html lang="en">

<head>
   <meta charset="UTF-8">
   <meta name="keywords" content="xxxx" />
   <meta name="description" content="xxxx" />
   <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
   <meta name="viewport"
       content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1,user-scalable=no,viewport-fit=cover" />
   <link rel="shortcut icon" href="./favicon.ico">
   <title>xxxx</title>
   <!--[if lte IE 9]>
   <script>location.href = 'https://www.baidu.com'</script>
   <![endif]-->
</head>

<body>
   <script>
       //监听资源加载错误
       window.addEventListener("unhandledrejection", function (e) {
           if (e.reason.message.includes('Loading chunk')) window.location.reload();
       }, true);
   </script>
   <noscript>
       You need to enable JavaScript to run this app.
   </noscript>
   <div id="root"></div>
</body>

</html>

在这里插入图片描述
可以看到主流浏览器都是支持的==

当检测到报错信息中含有Loading chunk,就代表着资源请求上的错误,这时你已经检测到了版本的升级,你可以做个有好的弹窗处理,提醒他点击重新加载,也可以像我一样暴力重载,记得让运维配置一下前端入口页的缓存设置为不缓存,防止入口页index.html也是缓存数据,类似于这样

server {
    listen       80 default_server;
    server_name  xxx.xxx.com;
    root         /app/xxx/html/;

    location ~ .*\.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm)$
    {
        expires      7d;
    }

    location ~ .*\.(?:js|css)$
    {
        expires      7d;
    }

    location ~ .*\.(?:htm|html)$
    {
        add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";
    }
}    
Vue

对于vue来说,在vue-router中有一个 router.onError(callback)的api,这就简化了我们处理的方式

	router.onError((error) => {
	  const pattern = /Loading chunk (\d)+ failed/g;
	  const isChunkLoadFailed = error.message.match(pattern);
	  const targetPath = router.history.pending.fullPath;
	  if (isChunkLoadFailed) {
	    router.replace(targetPath);
	  }
	});

我们需要做的就是捕获错误,重新渲染页面。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值