一个代码报错的溯源过程

前言

网络上大家都调侃程序员不看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源于好奇心,愿好奇心不减,代码永存,脑机永生。

相关推荐
二川bro5 分钟前
深度解析Vue项目Webpack打包分包策略 从基础配置到高级优化,全面掌握性能优化核心技巧
vue.js·webpack·性能优化
Dragon Wu5 分钟前
taro 小程序 CoverImage Image src无法显示图片的问题
javascript·小程序·前端框架·taro
搏博32 分钟前
Hbuilder X4.65新建vue3项目存在的问题以及解决办法
前端·javascript·vue.js·ecmascript
孩子 你要相信光1 小时前
vue3/vue2大屏适配
前端·javascript·vue.js
武昌库里写JAVA1 小时前
Iteration in Golang – How to Loop Through Data Structures in Go
java·vue.js·spring boot·学习·课程设计
娃哈哈哈哈呀2 小时前
Vue 3 动态 ref 的使用方式(表格)
前端·javascript·vue.js
小妖6664 小时前
el-breadcrumb 面包屑第一项后面怎么写没有分隔符
javascript·vue.js·elementui
LuckyLay11 小时前
Vue百日学习计划Day33-35天详细计划-Gemini版
前端·vue.js·学习
苹果酱056712 小时前
Golang中的runtime.LockOSThread 和 runtime.UnlockOSThread
java·vue.js·spring boot·mysql·课程设计
会飞的鱼先生12 小时前
vue2、vue3项目打包生成txt文件-自动记录打包日期:git版本、当前分支、提交人姓名、提交日期、提交描述等信息 和 前端项目的版本号json文件
前端·vue.js·git·json