25

这是我在野外使用 Webpack 代码拆分时遇到的一个意外问题:想象一下这种情况:

  1. 用户加载一个带有 Webpack 代码拆分的 React 应用程序,并加载了一些捆绑块
  2. 部署发生并且用户可能从服务器收到的任何未来块的内容都会更新(注意:以前的块在部署期间在服务器上被删除)
  3. 用户单击一个链接并加载一个新路由,该路由会触发更多捆绑块的加载。除了这些新块与用户浏览器已经加载的块不兼容并且应用程序由于运行时错误而中断

如何防止这种情况发生?

一种可能的解决方案是维护多个版本化的块集,但我想知道大型应用程序是否使用更简单的解决方案。

如果使用了preload-webpack-plugin,所有的块都可以被预取,但它们只会在很短的时间内保持缓存(在 Chrome 中为 5 分钟)。

4

4 回答 4

1

正如 Max Stoiber在spectrum.chat 上所写

ServiceWorkers 在进行代码拆分时非常方便!

我们使用@nekr 出色的离线插件在本地缓存所有当前包,因此无论服务器是否更新文件,ServiceWorker 将始终从本地缓存中提供文件。每小时它会检查服务器是否有更新,如果有可用更新,则从远程服务器下载所有新的捆绑包并在本地缓存它们。下次用户重新启动应用程序时,将使用新版本的应用程序!

https://github.com/NekR/offline-plugin

此解决方案意味着您的应用程序会预先下载所有块,这违背了在带宽方面进行代码拆分的目的,但至少您仍然保留了仅解析加载应用程序所需的块的好处,这对我来说很重要慢速设备。此外,浏览器刷新/缓存现在涉及 Service Worker 生命周期(请参阅https://developers.google.com/web/fundamentals/primers/service-workers/lifecycle上的“等待” )。

于 2019-03-19T16:15:30.523 回答
0

如果块文件名被散列,旧路由不会链接到旧散列块(大概仍然可用)并加载一切正常吗?

于 2017-08-03T20:52:16.273 回答
0

这个问题说得非常好。

我会补充说,“删除”可能不是正确的名称,具体取决于设置。

我对这个问题的最初反应是这是一个缓存问题。旧的块文件被拾取而不是新的。至少在我的情况下,它接近正在发生的事情,我有以下几点:

index.js

const Page1 = lazy(() => import('./page/Page1'));
const Page2 = lazy(() => import('./page/Page2'));

const main = () => {
  {
    '/page1': Page1,
    '/page2': Page2,
  }[window.location.href](); /* Some Render Router Implementation */
};
  1. V1 部署在 (https://my-domain/distribution_folder/*)
  2. 用户将加载 V1index.js
  3. V2 部署在 (https://my-domain/distribution_folder/*)
  4. 用户(未刷新)将使用其缓存的 V1index.js文件动态加载分块路由。
  5. 请求将被发送到 (https://my-domain/distribution_folder/{page_name}.{chunk_hash}.js)
  6. 将发生块错误,因为该唯一块将不再存在。

这很有趣,因为正在使用的提供商正在将流量迁移到新版本。所以我认为这将是它的结束,但我没有意识到任何用户仍然可以使用以前部署的版本 - 他们怎么知道?他们已经在使用该应用程序。浏览器已下载应用程序 ( index.js)。

解决方案实际上取决于您在哪里动态导入这些块。在上面的例子中,因为它们是页面路由,当我们找不到块时,当用户请求不同的页面时,我们可以进行硬刷新。但是,这假设您的Cache-Control标题设置正确。例如:

  • index.js->Cache-Control: no-store
  • page/{page_name}.{chunk_hash}.js->Cache-Control: public,max-age=31536000,immutable

我们可以使这些块不可变,因为有时它们在版本之间不会更改,如果它们不更改,为什么不使用缓存版本。但是,index.js不能存储在缓存中,因为这是动态加载内容的“路由器”,并且总是会改变。

优点

  • 没有更多的块加载错误
  • 我们不需要在第一页加载时加载所有内容
  • 没有服务人员,复杂性降低

缺点

  • 这种方法强制用户刷新

相关问题

于 2021-05-05T19:17:52.323 回答
-1

https://webpack.js.org/guides/caching/#output-filenames

确保浏览器获取更改文件的一种简单方法是使用 output.filename 替换。[hash] 替换可用于在文件名中包含特定于构建的哈希,但是最好使用在文件名中包含特定于块的哈希的 [chunkhash] 替换。

于 2017-08-03T20:52:20.333 回答