解决网页版本不一致导致的Failed to fetch dynamically imported module

1,598 阅读1分钟

错误分析

这个报错的来源的意思是远程模块导入失败
通常是因为网页处于活动状态时服务器资源更新了
然后html中引用的.js文件找不到了
这篇文章解决的就是这种通常情况
参考这两篇文章
stackoverflow.com/questions/6…
juejin.cn/post/722544…

基本思路

在每次打包时 同时在服务端和网页上设置时间戳
如果发生了这个异常 就对比服务端和当前页面的时间戳是否相同 不同就刷新网页

具体做法

项目是vue,vue-router,vite的
考虑把时间戳直接打在index.html上 并在router.onError内捕获

打包时打时间戳

// vite.config.js
    plugins: [
      {
        // 为生成的html加时间戳
        name: 'html-timestamp',
        transformIndexHtml (html) {
          return html.replace(
            /<html.*?>/,
            str => str.replace('html', `html data-ts="${Date.now()}" `),
          )
        },
      },
    ],

捕获异常

// @/router/index.js
router.onError((error, to, from) => {
  if (
    process.env.NODE_ENV === 'production' &&
    error.message.includes('Failed to fetch dynamically imported module')
  ) {
    fetch('')
      .then(res => res.text())
      .then(html => {
        const currentTs = document.querySelector('html').dataset.ts
        if (!html.includes(`data-ts="${currentTs}"`)) {
          const baseUrl = location.href.slice(0, -from.fullPath.length)
          window.open(baseUrl + to.fullPath, '_self')
        }
      })
  }
})

用fetch获取最新的html 与当前网页中的进行对比
这里不需要担心缓存的问题 响应头content-type为text/html的不会被浏览器自动缓存

to.fullPath前面加了个baseUrl 是因为存在多入口项目
比如本地的url是 http://127.0.0.0/test
生产环境是 http://xxx/client/test
要把http://xxx/client取出来拼接