一个代码报错的溯源过程

前言

网络上大家都调侃程序员不看warning,只看error,确实程序和人有一个能跑就行,一个小小的warning,还想参加蟠桃大会... 跑题了 最近在使用一个新的前端框架,发现某些情况下会出现一些意料之外的错误,整个排查过程有些波折,所以想记录一下~

问题的出现

wxt 一个快速开发浏览器插件的框架,其借助了vite构建能力,实现插件开发过程的热更新,对插件开发体验挺好的,支持任意UI描述框架。于是在尝试过程中,我使用了Vue来构建界面,但在content-script的开发过程中,偶然发现更新了script的内容之后,出现了两个问题:

  1. 浏览器热更新失效了,并且console打印了vue的warn。
  1. vite进程中断了,终端控制台报错:
vbnet 复制代码
 ERROR  "default" is not exported by "entrypoints/content/App.vue?vue&type=script&setup=true&lang.ts", imported by "entrypoints/content/App.vue".

问题的排查

查了一下框架github仓库的issue,有人提过content-script的UI无法渲染问题,但无人给出解决方案。那么有两个选择:自己排查 or 放弃。牛马人,当然要试一试排查。

这看似是两个不相干的问题,一个是丢失template、另外一个是没有默认导出属性;但Vue单文件都是由compiler-sfc解析器解析成js的,我们可以暂时先把它看成是一个问题:compiler-sfc解析异常。

排查目标确定

既然假设compiler-sfc解析异常,那就先从compiler-sfc解析产物入手,看它解析之后的js长啥样。

我改了handleClick方法的代码,App.vue文件解析之后,setup方法返回了__returned__变量,Hmm...render函数呢?不见了!难怪vue提示没有模板或者渲染函数。

既然产物有问题,那就对比一下正常情况下的产物应该是什么样的。

显然正常情况下单文件解析器是有返回渲染函数的,哪是哪里出问题了?

对比两者,可以看出异常产物有__returned__变量,那就直接进compiler-sfc看它是怎么处理的。

不是内联模板的情况下,就插入这段代码;没了,线索中断了吗?下一步?

换个方向思考,谁调用了compiler-sfc?在vite解析vue单文件中,使用了@vitejs/plugin-vue插件来解析。好!问题换成:难道@vitejs/plugin-vue在调用compiler-sfc的时候设置了这个inlineTemplate属性?

排查的深入

在查看@vitejs/plugin-vue源码之后,发现是在生产模式下才有可能把它设置成true,没了,线索又断了?

并没有,它引入了一个新方向,热更新(hot updated),并且我知道产物文件是打包生成的,那肯定涉及生产模式。好的,那么问题换成:生产模式与开发模式下,@vitejs/plugin-vue插件做了啥?

错误根源的发现

@vitejs/plugin-vue是在handleHotUpdategenScriptCode调用resolveScript的,显然一个是热更新用的,一个是打包编译用的。而resolveScript代码里面有两个前置return的判断条件:

  1. 没有script
  2. 存在缓存

resolveScript打了个日志,再跑一下复现流程,发现修改App.vue文件之后,执行了两次resolveScript第一次由热更新触发,第二次由build构建触发。

(忘记讲了,wxt框架针对插件的content-script脚本,是使用build构建之后,再插入到页面中,并且wxt启动的时候,是background.js content-script.js popup 三种插件模式都使用)

第二次执行resolveScript的时候,没调用compiler-sfccompileScript

查看代码上下文之后,发现热更新的时候,会设置缓存(热更新缓存用于只替换修改的内容,不会全量替换)

问题就出在了缓存这里,build编译代码的时候,拿的是热更新的代码,导致APP.vue解析成js丢失了一些数据。 那为什么vite的buildserver会共用@vitejs/plugin-vue的上下文呢?难道vite设计如此?进vite官网看看!

原来,vite的createServerbuild共用同个vite进程,那@vitejs/plugin-vue也只会在vite.config.ts中执行那一次,所以@vitejs/plugin-vue的cached也就被api.createServerapi.build 共用了。

所以,要解决此问题,只能从根源上解决,那就是将wxt的build模式,由node子进程去执行!

意外的解决方案

在最初看到vue单文件解析器的inlineTemplate属性之后,我在wxt框架源码中搜索inline/template/inlineTemplate,发现它默认会给vitebuild.sourceMap属性设置成内联inline。程序员的下意识思路就是,试试改成其他的会怎么样?

然后我将其改为false,开发插件要个嘚sourceMap啊...

结果,它就正常工作了!!! 到现在我还没找到sourceMap和解析器inlineTemplate的关联...

后续

给它issue回复了这个临时解决方案~ wxt-issue#538

写在最后

debug源于好奇心,愿好奇心不减,代码永存,脑机永生。

相关推荐
你真的可爱呀2 小时前
uniapp+vue3项目中的常见报错情况以及解决方法
前端·vue.js·uni-app
酒尘&7 小时前
Hook学习-上篇
前端·学习·react.js·前端框架·react
我命由我123458 小时前
VSCode - VSCode 修改文件树缩进
前端·ide·vscode·前端框架·编辑器·html·js
我命由我1234510 小时前
VSCode - VSCode 颜色值快速转换
前端·ide·vscode·前端框架·编辑器·html·js
qq_124987075310 小时前
基于SpringBoot+vue的小黄蜂外卖平台(源码+论文+部署+安装)
java·开发语言·vue.js·spring boot·后端·mysql·毕业设计
老前端的功夫10 小时前
移动端兼容性深度解析:从像素到交互的全方位解决方案
前端·前端框架·node.js·交互·css3
好好好明天会更好11 小时前
uniapp项目中视频播放控制对象
前端·vue.js
萌狼蓝天11 小时前
[Vue2]项目中 vue-draggable-resizable 列宽拖动问题修复(首次拖动列宽突然变得很小)
前端·javascript·vue.js·前端框架·ecmascript
带带弟弟学爬虫__11 小时前
ks安卓—did注册
前端·javascript·vue.js·python·网络爬虫
徐小夕@趣谈前端11 小时前
LuckyFlow:用Vue3实现的一款AI可视化工作流编辑器
vue.js·人工智能·编辑器