关于Vue Loading chunk {n} failed的一些思考

测试偶尔会出现这个问题,遂提出一个bug,从bug字面意思来看,有一个js的块加载失败了。丢失了一个${domain}/js/chunk-${hash}.js。

关于Vue Loading chunk {n} failed的一些思考

更新时间:2020-06-02 14:52:43

0x1 问题

Loading chunk {n} failed

测试偶尔会出现这个问题,遂提出一个bug,从bug字面意思来看,有一个js的块加载失败了。丢失了一个${domain}/js/chunk-${hash}.js

为什么会丢失?

为什么会偶发?

同类问题

Vue项目中出现Loading chunk {n} failed问题的解决方法

点击切换路由的时候,有时候会报错

本文大量引用了17khba点击切换路由的时候,有时候会报错的回答。

0x2 偶发性原因

前提:部署方式为删除上一次构建的资源文件,替换成新的打包文件。

  1. 新版本部署前,有用户正在你的网页中
  2. 然后你部署了新版本,而且是删除原有资源,比如 hash 为bgt78d的资源不见了,但此时用户的index.html模板中还是记录的bgt78d的资源地址
  3. 这时用户在他现有的页面中进行路由切换,前端路由切换
  4. 这不会触发去重现获取 index.html,所以老的 index.html中的 chunk 信息生效
  5. 这个时候如果访问已经访问过的路由,这些路由中的 chunk 已经被浏览器缓存,路由(页面)能正常,虽然它可能使用的是过时的资源(就你上一个版本发布的资源)
  6. 但是当请求之前没有请求过的路由,因为懒加载的关系,这些路由对应的组件 chunk 没有缓存,根据老的 chunk 对应信息,去请求老的静态资源,而老的静态资源又已经由于你的部署顶替掉了,于是出现找不到的问题
  7. 刷新就可以,因为刷新重现获取了一遍 html 文档,chunk 对应信息也就刷新了

0x3 简单解决思路

上面也提到了刷新页面,但是仅仅捕获到错误就刷新,很可能出现死循环,因为浏览器或者类似于Nginx缓存设置的原因,浏览器不一定每次刷新去获取新的index.html
所以结合重试次数和重试间隔来重试会比较好

0x4 更好的解决思路

  • 构建的时候静态资源路径带上版本信息,这个有很多方法
    • 比如路径中携带,比如原来请求 /static/js/balabal.[hash].js,现在/[version]/static/balabal.[hash].js
  • 部署的时候不用顶替部署,而是保留老版本,有很多方式,比如
    • 如果是裸机部署,可以在 web 服务器根目录下,新建 version 对应的目录,然后部署到这个目录
    • 如果是 docker 容器顶替部署,可以在构建前端的时候将前端资源打成 tar 包上传到某个地方,这样在打包新版本的 docker 镜像的时候,可以拉取上一个版本的 tar 包,也打包到镜像中,这样 docker 中也能有两个版本的资源,通过版本路径区分下
  • 这样的情况下,原有页面的用户还是会访问到老的资源,虽然可能版本落后,但是不会出错,部署后新打开的页面就会访问新的资源

PS.如果不想暴露 version,可以把 version 做一个 hash 或者混淆

0x5 实现

查看Vue-cli配置文档,

assetsDir

  • Type: string

  • Default: ''

    放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录。

    提示

    从生成的资源覆写 filename 或 chunkFilename 时,assetsDir 会被忽略。

只需要给assetsDir设置一个版本号文件夹,每次发布新版的时候,不删除这个文件夹就行。可以选择性的保留最近几次版本的静态资源文件。

使用 npm 版本号管理进行配合。

${app}/vue.config.js

const { version } = require('./package.json')

module.exports = {
  // 放置生成的静态资源 (js、css、img、fonts) 的 (相对于 outputDir 的) 目录。
  assetsDir: `./${version}`,
  ...
}

打包命令加上--no-clean。作用是不清除上次打包生成的dist目录。

vue-cli-service build --no-clean

dist

0x6 结论❗

问题到这里基本已经解决了,不过仍然出现了一些可以优化的地方。比如我没有清除上次打包的dist目录,如果在${app}/public目录下引入的一些静态资源后期版本已经删除了,由于我们没有删除dist目录,不需要的资源仍然存在部署的服务器上。、

如果有很好的方案欢迎指出或者讨论。谢谢你的阅读~💗

关于我

SunSeekerX,前端开发、Nodejs开发、小程序、uni-app开发、等等

喜欢探讨技术实现方案和细节,完美主义者,见不得bug

Github:https://github.com/SunSeekerX

个人博客:/

个人在线笔记:https://sunseekerx.yoouu.cn/