一次vite热更新不生效问题排查

vite热更新不生效

  • keep-alive导致的不生效:开发模式下禁用即可
  • jsx导致热更新不生效

jsx导致不生效问题

vue2项目从接入vite4(vite-plugin-vue2只支持到vite4)后,陆续有些页面不能热更新,一直未找到原因。

以下记录一次排查热更新无效的过程:

  1. 多轮比对可以热更新页面和不能热更新页面的代码情况,未找到解决方案
  2. 询问chatGPT为什么部分页面能热更新,其中给出了用vite-plugin-inspect检查代码的方案,了解到了这个插件
    • vite-plugin-inspect插件用于展示业务组件是如何被vite各种插件进行转换的
    • 经过多轮比对能更新和不能更新页面编译后差异情况,发现不能更新页面都是jsx页面
  3. vite-plugin-vue2支持jsx,去到github查找issue,有人提出这个jsx热更新问题,似乎没有被解决
  4. 升级插件为官方@vitejs/plugin-vue2,@vitejs/plugin-vue2-jsx,依然存在问题
  5. 升级到vite6,问题解决

思考:如果依然未解决,是否可以自行研究vite热更新原理及vite-plugin-vue2源码,自行解决这个问题呢?

再次问题排查

参考: Vite5.0 moduleGraph软失效(soft invalidate)浅析

Vite 源码(六)解析 importAnalysis 插件

使用过程中发现依然有部分文件不能热更新,比如add.vue,改模板内容会重新加载add.vue,但是改js内容,只会重新加载add.vue,不会加载js文件add.vue?type=script&lang.jsx

add.vue,add.vue?type=script&lang.jsx有什么区别?明明只是查询参数不同,为何是两个不同的文件?只是vite启动了一个服务器transformMiddleware,同时会拦截.vue请求,并根据不同的查询参数生成不同的文件,此文件磁盘中不存在。类似于调用后端接口动态拼接文件内容并返回

排查过程:用webstorm的调试模式启动vite,断点调试

  • vite版本:6.3.5
  • vite源码文件dist/node/chunks/dep-DBxKXgDP.js
  • vite监听文件变化watcher.on("change"
  • 执行onHMRUpdate,
  • 在handleHMRUpdate收集需要热更新的模块hotMap,执行更新hmr(environment),然后updateModules,然后使模块失效invalidateModule(通过添加失效标记),
    • hotMap一般只包含修改的一个文件
    • hotMap.options.modules 需要热更新的模块
    • module.importedModules内部导入的模块,也需要热更新,比如add.vue中lang=jsx中的js内容就是被处理成一个单独的import导入的,此时js改动也需要把js文件热更新
  • invalidateModule 使模块失效,就是给模块增加加个时间lastHMRTimestamp,后续这个值会被用到
    • 使得add.vue失效,同时遍历其父引用importers,使父引用失效,过程中会有个seen缓存,避免循环引用问题
    • add.vue -> .auto.js -> router/index.js -> main.js -> router/router.js -> store/permission.js -> store/index.js -> add.vue?script&lang.jsx
    • 转了一圈,终于找到了add.vue?script&lang.jsx,这算是bug吗,不能直接找一下add.vue内部的引用吗。
    • 如果移除add.vue?script中的store引用,果然js热更新失效
  • 给客户端发送socket消息通知更新
  • 客户端通过import动态获取文件add.vue,同时add.vue中的import main from 'add.vue?type=script&lang.jsx&t=123253543',其中的时间戳t只有被标记为热更新时才会被vite添加,否则不会加载这个文件
  • vite服务端拦截请求,transformMiddleware -> transformRequest -> doTransform -> environment.moduleGraph.getModuleByUrl(url)
  • 执行插件的load和transform: loadAndTransform,获取转换后的结果
  • 在vite:import-analysis插件(vite内置插件)中根据lastHMRTimestamp是否大于0执行动态替换.vue文件中的import语句,加入时间戳获取新文件
  • 获取到新文件后,重新注册组件或者替换render和options等属性后执行render或者$forceUpdate

草率的结论:如果add.vue?script中没有引入store,又没有其他方式通过add.vue一步步的链接到add.vue?script,则add.vue?script不会被标记为热更新,解决方案便是找到add.vue的某个父级引用,然后在add.vue中引入它形成一个循环引用?

如果有更好的解决方案还请评论告知。

相关推荐
童先生3 小时前
Nginx + Vue/React 前端 + API:防止路径混淆漏洞与跨域问题实战分享
前端·vue.js·nginx
Stringzhua5 小时前
Vue数据的变更操作与表单数据的收集【6】
前端·javascript·vue.js
万少5 小时前
可可图片编辑 HarmonyOS 上架应用分享
前端·harmonyos
你的人类朋友6 小时前
git常见操作整理(持续更新)
前端·git·后端
无羡仙6 小时前
Webpack 核心实战:从零搭建支持热更新与 Babel 转译的现代前端环境
前端·webpack·前端框架
你的人类朋友6 小时前
git中的Fast-Forward是什么?
前端·git·后端
初遇你时动了情6 小时前
uniapp vue3 ts自定义底部 tabbar菜单
前端·javascript·uni-app
JarvanMo6 小时前
天塌了?Flutter工程总监跑去苹果了?
前端
烛阴8 小时前
掌握 TypeScript 的边界:any, unknown, void, never 的正确用法与陷阱
前端·javascript·typescript
Jerry8 小时前
迁移到 Jetpack Compose
前端