一个代码报错的溯源过程

前言

网络上大家都调侃程序员不看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是在handleHotUpdate和genScriptCode调用resolveScript的,显然一个是热更新用的,一个是打包编译用的。而resolveScript代码里面有两个前置return的判断条件:

  1. 没有script
  2. 存在缓存

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

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

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

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

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

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

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

意外的解决方案

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

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

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

后续

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

写在最后

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

相关推荐
码艺-Alimjan6 小时前
Tauri 源码备份 · 打包 & 解压 总结,源码收集之路
前端·javascript·vue.js
顽疲8 小时前
Java vue 养老系统源码详解:月账单 care_month_bill 与 Quartz 扣费 Job 实践
java·开发语言·vue.js·vue养老·springboot养老·java养老
看浪的路人10 小时前
第2讲:ReAct 模式从零实现——不用框架,手写一个 Agent 内核
前端·react.js·前端框架
毕业设计70310 小时前
(免费领源码)基于node的学生公寓管理系统06412- java、PHP、python、C#、小程序、大数据、单片机、网络工程等)
vue.js·mysql·node.js·maven·mybatis·express·b/s
古夕10 小时前
地址变了,页面是空的:一次 Vue Router 菜单切换复盘
前端·vue.js
沙漏无语14 小时前
pnpm 安装@vue-office包的幽灵依赖问题解决
前端·javascript·vue.js
雪芽蓝域zzs15 小时前
第 9 节:面积测量(测面工具)
vue.js
℘团子এ15 小时前
vue2中自定义指令的使用
前端·javascript·vue.js
℘团子এ17 小时前
vue3中自定义指令的使用
前端·javascript·vue.js
m0_5873830019 小时前
碰碰好评卡功能落地实战 从需求梳理到上线部署全流程实操指南
java·linux·服务器·前端·javascript·vue.js·人工智能