使用React-Snapshot创建React应用并进行预渲染静态文件

8
我正在使用create react app和react-snapshot为我的路由预渲染静态标记。例如"/", "/signIn", "/signUp"分别生成index.html, signIn.html, signUp.html。但是,我面临的问题是无论我访问哪个路由,最初都会提供从根路由"/"生成的静态index.html,然后提供正确的静态路由文件,最后提供main.js捆绑文件(请参见gif)。如果我只是从打包好的main.js中提供应用程序,这样做就没问题了。但是,由于我想使用静态预生成的html文件,那么我该如何禁用服务工作线程在某些已经具有静态html文件的路由上提供index.html呢?
更新:如果我从create react app中删除服务工作线程,则应用程序可以很好地加载路径的静态文件。然而,我希望保留PWA功能的服务工作线程功能。 更新2: Chrome浏览器 上,根路由静态标记的快速闪烁仅在每个路由上发生一次。在第一次闪烁后,Chrome浏览器缓存似乎修复了它,此外,如果我从Chrome开发工具禁用缓存并尝试转到新路由,则根路由的闪烁会重新出现。 在 Firefox浏览器 上,无论如何问题都存在,每次路由更改或刷新时,根路由静态标记的短暂闪烁都会发生。

如何在不删除服务工作者的情况下避免在所有路由上最初呈现index.html?

更详细地说: 在启用服务工作者的情况下,以下代码会呈现在所有路由的页面源的body中:
 <body>
 <script>window.react_snapshot_state = {};</script>
 <noscript>You need to enable JavaScript to run this app.</noscript>
 <div id="root" data-react-checksum="-928641672"><div data-reactroot="" class="sc-cSHVUG hyLStb"><div class="sc-fjdhpX dIRAsX"><ul class="sc-gqjmRU koKaUp"><li><a class="navItemActive sc-VigVT cZrGwO" href="/"><!-- react-text: 6 --> <!-- /react-text --><!-- react-text: 7 -->Home<!-- /react-text --></a></li><li><a class="sc-VigVT cZrGwO" href="/aboutUs/"> About US</a></li><li><a class="sc-VigVT cZrGwO" href="/faq/"> FAQ</a></li></ul><div class="sc-jzJRlG cLytIk"><button class="ui basic circular compact icon button sc-jTzLTM jfwzMH"><i aria-hidden="true" class="user circle icon"></i></button><button class="ui basic circular compact icon button sc-jTzLTM jfwzMH"><i aria-hidden="true" class="add user icon"></i></button></div></div><!-- react-empty: 17 --><div><div style="opacity: 1;"><div class="sc-bdVaJa eRTdVS">Home</div></div></div></div></div><script type="text/javascript" src="/static/js/main.04df5475.js"></script></body>

如果我移除了Service Worker,"/signIn"路由会在页面源代码的主体中呈现以下内容:
<body>
 <script>window.react_snapshot_state = {};</script>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root" data-react-checksum="143569200"><div data-reactroot="" class="sc-cSHVUG hyLStb"><div class="sc-fjdhpX dIRAsX"><ul class="sc-gqjmRU koKaUp"><li><a class="sc-VigVT cZrGwO" href="/"><!-- react-text: 6 --> <!-- /react-text --><!-- react-text: 7 -->Home<!-- /react-text --></a></li><li><a class="sc-VigVT cZrGwO" href="/aboutUs/"> About US</a></li><li><a class="sc-VigVT cZrGwO" href="/faq/"> FAQ</a></li></ul><div class="sc-jzJRlG cLytIk"><button class="ui basic circular compact icon button sc-jTzLTM jfwzMH"><i aria-hidden="true" class="user circle icon"></i></button><button class="ui basic circular compact icon button sc-jTzLTM jfwzMH"><i aria-hidden="true" class="add user icon"></i></button></div></div><!-- react-empty: 17 --><div><div style="opacity: 1;"><div><div class="sc-EHOje bssfxk"><div class="sc-EHOje bssfxk"><form class="ui large warning form sc-ifAKCX ljuaXJ"><div class="field"><label></label><input type="email" placeholder="email" name="email" value=""></div><p class="sc-bxivhb dXOlfT">error</p></form><form class="ui large warning form sc-ifAKCX ljuaXJ"><div class="field"><label></label><input type="password" placeholder="password" name="password" value=""></div><p class="sc-bxivhb dXOlfT">error</p></form></div><p class="sc-dnqmqq ccTWaR"></p><div><div class="sc-gzVnrw cCgvhR"><button class="ui basic button sc-iwsKbI Vfjvd"><!-- react-text: 37 -->Login<!-- /react-text --><!-- react-text: 38 --> <!-- /react-text --></button><div class="sc-gzVnrw cCgvhR"><!-- react-empty: 40 --><div class="ui horizontal divider" style="width: 220px;">Or</div><div class="sc-bZQynM kECAnI"><button class="ui google plus button" style="text-transform: capitalize;"><i aria-hidden="true" class="google icon"></i><!-- react-text: 45 --> Google<!-- /react-text --></button><button class="ui facebook button" style="text-transform: capitalize;"><i aria-hidden="true" class="facebook icon"></i><!-- react-text: 48 --> Facebook<!-- /react-text --></button></div></div></div><div><p class="sc-htoDjs dErAlA">forgot your password ?</p></div></div></div></div></div></div></div></div><script type="text/javascript" src="/static/js/main.04df5475.js"></script><iframe style="display: none;"></iframe>

GiF展示了我尝试访问“/signIn”路由,并注意到在实际表单渲染出来之前,词语“home”(“/”路由的静态标记)会暂时出现。请保留HTML标签。

enter image description here

2个回答

6
问题在于 Create React App 中的 Service Worker(SW) 默认只缓存 static folderindex.html 的内容。我的使用 react-snapshot 预渲染的 .html 文件从未被 SW 缓存。在 Create React App 中,SW 也被设置为对所有未知 url 提供 index.html,因此它提供了根路径下的静态文件 index.html。通过更改 package.json 中的构建命令,我通过覆盖 service-worker.js 文件来解决了这个问题,如下所示:

"build": "react-scripts build && react-snapshot && sw-precache --config=sw-precache-config.js"

其中,我的 sw-precache-config.js 如下所示:

module.exports = {
  staticFileGlobs: [
    './build/**/**.html',
    './build/images/**.*',
    './build/static/**',
  ],
  dontCacheBustUrlsMatching: /\.\w{8}\./,
  swFilePath: './build/service-worker.js',
      // For unknown URLs, fallback to the index page
  navigateFallback: './200.html',
      // Ignores URLs starting from /__ (useful for Firebase):
      // https://github.com/facebookincubator/create-react-app/issues/2237#issuecomment-302693219
  navigateFallbackWhitelist: [/^(?!\/__).*/],
      // Don't precache sourcemaps (they're large) and build asset manifest:
  staticFileGlobsIgnorePatterns: [/\.map$/, /asset-manifest\.json$/],
  stripPrefix: './build'
}

静态内容已生成,我按照描述进行了所有更改。但它对我没有用。Chrome仍然显示index.html内容。 我的preCacheConfig更新得很好。 - HalfWebDev

3
如果你拥有从react-snapshot生成的所有标记列表,你可以手动设置重写规则,然后为其余内容添加一个回退规则。
例如:
"rewrites": [
  {
    "source": "/signup",
    "destination": "/signup.html"
  },
  {
    "source": "/orders",
    "destination": "/orders.html"
  },
  {
    "source": "**",
    "destination": "/index.html"
  }
]

2
这并没有解决问题,index.html仍然在所有路由上首先呈现。 - jasan
这些更改需要在serve.json中完成。serve.json不会在CRA的引导程序中生成,您需要将其添加到public文件夹中。此外,您需要使用serve -c serve.json build更新serve命令。 如果没有服务工作者,这将运行良好。 - Gaurav Jain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接