• react h5 发版白屏问题解决方案


    背景:h5应用每次发布之后会有部分用户白屏
    React v5

    1. 优化路由加载时间 app.jsx
    render() {
        if(this.state.loading) {
          return <PendingPage />
        }
        return (
          <Router>
            <Suspense fallback={<PendingPage />}>
              {
                this.state.showPage ?
                <Switch>
                  {routes.map((route, i) => (
                    <RouteWithSubRoutes key={i} {...route} />
                  ))}
                </Switch>
                : <PendingPage />
              }
            </Suspense>
          </Router>
        );
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    2. 自刷新模式build_version-react路由
    const path = require("path");
    const fs = require("fs");
    
    // 将当前时间戳写入json文件
    let json_obj = { build_version: new Date().getTime().toString(),status:200,success:true };
    fs.writeFile(
        path.resolve(__dirname, "./public/json/build_version.json"),
        JSON.stringify(json_obj),
        function(err) {
            if (err) {
                return console.error(err);
            }
            console.log("打包字符串写入文件:public/json/build_version.json,成功!");
        }
    );
    // "build": "node create_build_version_json.js && react-app-rewired build",
    // 写入package.json 打包先执行次node.js
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    增加react路由守卫,在每次切换页面去请求生成的时间戳

    // FrontendAuth.js
    import React, { Component } from "react";
    import { Route, Redirect } from "react-router-dom";
    import axios from "axios";
    
    class FrontendAuth extends Component {
      constructor(props) {
        super(props);
      }
      render() {
        const { routerConfig, location } = this.props;
        const { pathname } = location;
        
        axios.get("/json/build_version.json?v=" + new Date().getTime().toString()).then(res=>{
          let newBuildStr = res.data.build_version;
          let oldBuildStr = localStorage.getItem("build_version") || "";
          if (oldBuildStr !== newBuildStr) {
              localStorage.setItem("build_version", newBuildStr);
              window.location.reload();
          }
        })
    
        const targetRouterConfig = routerConfig.find(
          (item) => item.path === pathname
        );
        if (targetRouterConfig) {
          const { component } = targetRouterConfig;
          return <Route exact path={pathname} component={component} />;
        }
      }
    }
    
    export default FrontendAuth;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    // app.jsx
    render() {
        return (
          <Router>
            <Suspense fallback={<PendingPage />}>
                <Switch>
                  <FrontendAuth routerConfig={routerMap} />
                </Switch>
            </Suspense>
          </Router>
        );
    }
    // router/routerMap.js-路由集合
    const Index= React.lazy(() => import('../pages/index/index.jsx'));
    export default [
        {
            path: '/index',
            component: Index,
        }
    ]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    3. webpack打包 生成的js版本号_v=hash值(config-overrides.js)
    config.output.filename = 'static/js/[name].[contenthash].js?_v=[contenthash]'
    config.output.chunkFilename = 'static/js/[name].[contenthash].chunk.js?_v=[contenthash]'
    // 某些浏览器可能会忽略.js?v=xxxx
    
    • 1
    • 2
    • 3
    4. ng配置不缓存html(已存在)
    #对html文件限制缓存        
    location ~ .*\.(html)$ {            
        add_header Cache-Control no-store;
        add_header Pragma no-cache;        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    5. 前端html header(index.html)(已存在)
    <meta
      http-equiv="cache-control"
      content="no-cache,no-store, must-revalidate"
    />
    <meta http-equiv="Pragma" content="no-cache" />
    <meta http-equiv="Cache" content="no-cache" />
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    6. 灰度发布 / 服务器增加一台灰度服务器,运维控制流量切换服务器,着步切换

    注: 目前灰度方案由前端cookie控制,但是必须要先全量发布之后才能走灰度,灰度方案不支持。
    根据自己的情况。

    7. 新增js报错监控,如果检测到js报错,跳转空页面。手动点击登录。(app.jsx)
    componentDidCatch(error, info) {
        if (String(error).includes('Loading chunk')) {
          // 解决灰度切换js缺失的问题
            window.location.reload();
        } else {
          // 容错机制-会导致所有的报错回到此页面-再考虑一下!
          // window.location.replace('/404')
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 相关阅读:
    两表union 如何保证group by 字段唯一
    商业计划书PPT怎么做?这个AI软件一键在线生成,做PPT再也不求人!
    小度打头阵,百度大模型能否“赋能万物”?
    Selenium - 自动化测试框架
    【seo规则优化-语义化标签-set用法】
    多线程(二)多线程的锁机制(java)
    中国生态系统服务空间/食物生产、土壤保持、水源涵养、防风固沙、生物多样性、碳固定
    JAVA每日小知识(关于excel下载时插入和stream流遍历优化)
    gcc -static 在centos stream8 和centos stream9中运行报错的解决办法
    flinkcdc监控sqlserver,数据库的表中该字段是空值,而cdc中该字段的值是'N,不一致
  • 原文地址:https://blog.csdn.net/zqh862735956/article/details/134059465