调试与避坑手册
本教程共 45 篇 · 第 40 篇 · 更新于 2026-08-13 · 约 4 分钟阅读
本节目标:掌握「先判断环境、再按顺序排查」的调试方法论,学会定位扩展开发中最高频的几类错误,并了解全册已经讲过的坑点清单。
第一步:错误属于哪个环境
扩展代码跑在多个环境里,每个环境有自己的 Console。只盯着启动 WXT 的终端,是调试最常见的误区——终端只报构建和类型错误,运行时报错要去浏览器里看。
| 问题位置 | 打开方式 |
|---|---|
| 弹窗(popup) | 右键弹窗内部 → 检查 |
| 选项页 / newtab / tabs | 在对应页面打开 DevTools |
| 侧边栏 | 检查侧边栏面板页面 |
| 后台(background) | chrome://extensions 里点击 service worker |
| 内容脚本 | 在匹配的目标网页打开 DevTools |
| Firefox 后台 | about:debugging 里检查该扩展 |
| 构建 / 类型错误 | 运行 WXT 的终端 |
先复现,再记录:浏览器、入口点、URL、是否刚刷新过扩展、准确报错文本。记录越全,定位越快。
推荐检查顺序
小改动完成后,按成本从低到高:
- typecheck——类型错误最先暴露;
- lint;
- 涉及已有逻辑时,跑最窄的单元测试(如 §36 所述);
- 涉及 wxt.config.ts、入口点、public 资源、manifest 时,跑 build;
- 完整发布检查:lint → typecheck → test → build。
这些命令替代不了真实 UI、OAuth 和跨浏览器的人工验证。
高频错误定位
Cannot find module ‘#imports’ 或 WXT 类型缺失
生成类型没跟上。重新跑 wxt prepare(postinstall 里通常已配置)。确认 tsconfig.json 继承了 .wxt/tsconfig.json——不要手写一个假的 #imports 声明去骗编译器(如 §29 所述)。
内容脚本没有运行
按顺序查六项:
- 文件是否在入口点目录、命名是否符合规则(如 §11 所述);
- 当前 URL 是否匹配 matches;
- 扩展和目标标签页是否都刷新过;
- 是否在目标网页的 Console 里看日志(不是扩展页);
- 生成 manifest 里是否包含该脚本;
- 开发模式下内容脚本是动态注册的,不进 manifest,这是正常现象。用 service worker 控制台确认:
await chrome.scripting.getRegisteredContentScripts();
Extension context invalidated
扩展重载后,旧页面里残留的脚本会报这个错。刷新目标标签页;更根本的解法是用内容脚本的 ctx 管理监听器与异步任务,失效时自动清理(如 §14 所述)。
background 日志找不到
background 的 console 不在弹窗里,去 chrome://extensions 点 service worker 打开。MV3 worker 休眠是正常行为(如 §10 所述),先触发对应事件或消息,再观察日志。
跨域或网络错误
检查四处是否一致:.env 里的 API 地址、生成 manifest 的 host permissions、后端 CORS、认证服务的 trusted origins。改 .env 后必须重启开发进程。不要用 <all_urls> 掩盖配置问题。
manifest 配置改了没生效
WXT 的 HMR 不总能替换扩展安装清单。停掉开发进程、重新启动、在扩展管理页刷新,必要时移除旧的临时扩展再加载。
弹窗里的下拉菜单被裁剪、主题不对
在真实弹窗里检查,不要直接开 popup.html 标签页(环境不同)。确认 portal 所在文档的 有 dark class,检查固定宽度与滚动容器。
检查产物,别把 build 当源码
构建后打开 .output/{browser}-{mv}/manifest.json,核对权限、入口、版本、图标与 _locales(如 §38 所述)。build 目录是生成物,修改它不等于修了源码。
日志安全
允许记录:功能阶段、状态码、不含隐私的错误类型。禁止记录:bearer token 与 Authorization 头、密码与表单完整内容、OAuth 完整回调 URL、未经需要的页面正文与浏览历史。
全册坑点速查
下面是 mkext 项目代码审查里真实踩过的坑,详细展开都在前文各章,这里只列入口:
- 内容脚本清理:WXT 不会调用 main() 的返回值,清理逻辑要挂在 ctx.onInvalidated 上(§14);
- 重扫风暴:高频 DOM 变更用 ctx.setTimeout 防抖(§14);
- OAuth 错误区分:getAuthToken 的错误码与 UI 文案要一致,用户取消要单独识别(§35 的 Firefox 兼容部分);
- token 缓存失效:后端拒绝 token 后要调 removeCachedAuthToken,否则重试永远用死 token(§35);
- Chrome 专属字段混入 Firefox 包:key、oauth2 等要按浏览器剥离(§35);
- 依赖废弃 API:升级依赖时留意,如 Zod 4 已废弃 z.nativeEnum(mkext 的 env.config.ts 就踩过);
- worker 内存不持久:状态要进 storage,别指望内存(§10、§18);
- 消息不可信:跨上下文消息入参按 unknown 校验(§17);
- 类型导入:避免无谓 re-export 拖入无关代码,注意 bundle 体积(§22)。
调试心态
先复现,再二分:是构建问题、权限问题,还是 URL 不匹配?三类问题在生成 manifest 里都能看到痕迹。检查产物而不是猜,是调试效率最高的习惯。
小结
- 先复现,再二分:构建问题、权限问题、URL 不匹配,在生成 manifest 里都有痕迹。
- 各环境(后台 / 内容脚本 / 弹窗 / 扩展页面)的 Console 是分开的,先找对地方。
- 高频坑点速查表挂在 mkext 的真实代码审查上,遇到问题先查一遍再动手。