Skip to main content
只要轮询一个 JSON 文件,就能知道一个会话是就绪、出错,还是已经没了。 每一次 dev、start、preview 和 build 运行,都会在每次编译时原子地写入 dist/extension-js/<browser>/ready.json。当前契约是 schemaVersion: 2。 没有构建产物的 preview 会加载源码目录,但仍然把契约写到项目的 dist/extension-js/<browser>/ready.json,并带有已构建的 preview 所带的全部浏览器字段。

状态

两阶段就绪

status: "ready" 只意味着编译完成,仅此而已。浏览器可能还在启动,service worker 也可能还没有连上。 act 类工具(eval、storage、reload、open、inspect)需要第二个阶段。要等到契约里带上 runtime: "attached" 和一个 executorAttachedAt 时间戳之后,再去驱动扩展。 attach 这个戳是幂等的,并且能挺过重新编译。一次 attach 也会清除之前的 extension_load_refused 状态,因为执行器就跑在被托管的浏览器里面。

字段参考(schema v2)

始终存在的字段: 在已知时才出现的字段:

错误状态

code 字段给失败类别命名。对自动化来说有四个代码要紧: 一次加载被拒会活过下一次成功编译。只有一次新的运行(starting)或者一次真正的执行器 attach 才能把它清掉。 浏览器在扩展加载之前就退出的 dev 会话,会跨重新编译一直停在 error,因为重新编译不会把浏览器带回来。启动失败同样会活过重新编译,直到真的有一个浏览器启动,或者开始一次新的运行。

用 —wait 等待

extension dev --wait 和 extension start --wait 每 250 毫秒轮询一次契约,并在它报告 ready 时退出。配合 --output json 可以拿到机器可读的结果。 等待循环拒绝相信过期文件。每次读取都会跑三项检查:
  1. command 字段必须与正在等待的命令一致。
  2. pid 必须还活着。对 dev 来说,生产者已死就一定意味着文件过期,所以轮询会继续。
  3. 对 start 来说,只有当契约足够新鲜时,才接受一个已死的 pid。新鲜的意思是 ts、compiledAt 或 startedAt 在最近 60 秒之内。
超时会以 E_READY_TIMEOUT 退出。处于 error 状态的契约会带着它的 message 让等待失败,结果里的 error.code 由契约自身的代码解析而来: 带 browserLaunchFailedCode: "E_BROWSER_BINARY_INVALID" 或 "E_FLAG_NOT_SUPPORTED_HERE" 的 browser_launch_failed 契约会让等待以该代码和 status: "usage" 失败,而不是 E_BROWSER_LAUNCH。

把会话文件连起来

同一个目录里还放着 events.ndjson(编译时间线)和 logs.ndjson(扩展的控制台输出)。这两个文件里的每一行都带着来自 ready.json 的 runId。 events.ndjson 在每次运行开始时被清空,所以它永远只描述当前这次运行。事件类型有 compile_start、compile_success、compile_error、browser_exited、browser_launch_failed 和 shutdown。browser_exited 这一行对应启动器盖下的退出戳,带 exitCode、exitSignal 和 browserExitedAt,所以时间线会说明浏览器是什么时候、怎么走的。在它之后,每个 act verb 都会回答 E_CONTROL_UNAVAILABLE,并指出这次退出和需要的重启,因为在新的 dev 会话重新启动浏览器之前,不会有 service worker 重新连上。browser_launch_failed 这一行对应启动失败的戳,带 browserLaunchFailedAt 和 reason。

示例

下一步