Skip to main content
为每次文件变更选择最轻量的更新策略,让开发保持快速。 需要在每次文件变更后获得快速反馈吗?Extension.js 会自动选择最安全、最快的更新路径:
  • HMR(热模块替换):当模块更新是安全的时候使用
  • 分类重载(full、service worker、content scripts,或仅通知的 page):当运行时资产发生变化时使用
  • 需要重启错误/警告:当入口结构发生变化时

重载前置条件(devtools 设置对话框)

在评估重载行为之前,请按照 Extension.js devtools Confirm setup 对话框中相同的检查项进行确认: 如果跳过其中任一步,即使构建流水线正常,重载行为也可能表现不一致。

重载层级

1) 热模块替换(最快路径)

当代码可以在不重启扩展后台进程和事件监听器的情况下完成更新时,Extension.js 使用 HMR。 常见示例:
  • 挂载在扩展 HTML 页面上的脚本(通过注入的 HMR 包装器接受更新)
  • 非 service-worker 流程中的后台脚本模块
  • 通过 userScripts API 注册的脚本
  • 在受支持的 content-script/运行时包装器中的 CSS 更新

2) 分类重载

当一次变更需要的不只是 HMR 时,Extension.js 会把它归入四种重载类型之一: 这个判定来自编译器的 chunk 图,而不是文件名,并遵循固定顺序:
  1. 强制 full。manifest.json_locales/ 下任何内容的修改,总是归类为 full,无论还改了什么。
  2. chunk 归属。 Extension.js 会查出每个变更源文件属于哪些 chunk。位于 background/ chunk 中的源文件意味着 service-worker,位于 content_scripts/ chunk 中的源文件意味着 content-scripts
  3. 变更的静态资产。 有些变更文件存在于输出目录里,却不属于任何 chunk:图标、web-accessible 资源、DNR 规则集。它们会强制 full,好让浏览器从磁盘重新读取。
  4. 名称启发式。 仅用于 chunk 图不认识的源文件:路径匹配 backgroundservice worker 模式的归类为 service-worker
  5. content 兜底。 如果 manifest 声明了 content script,剩下的未知变更会重新注入每一个 content-script 入口。
  6. 仅通知的 page。 其余一切都是 page 指令:刷新由 livereload 负责,重载通告仍会发出。
同时存在于 service-worker chunk 和 content-script chunk 中的源文件会向两条路径扇出。一次保存会触发 SW 重启,并在同一条分类指令里带上待重新注入的过期 content-script 入口。 每次开发期重载都会由 dev 服务器生成一个统一的上下文标签来通告。格式是 context (fileA, fileB +2 more),例如 service_worker + content_script (shared/api.ts)。同一个标签会原样出现在 CLI 的 stdout、页面 devtools 控制台以及 devtools 的小药丸里,因此你可以在这三处之间对应同一次重载,不用靠猜。
如果重载后浏览器仍然提供缓存的过期 service worker,dev 服务器会检测到版本不一致并自动重新同步扩展。你不需要手动移除再重新添加扩展来恢复。
为什么开发模式下 content script 的文件名带哈希? Chrome 会激进缓存 chrome-extension:// 资源。即便完整地重载扩展后,像 content-0.js 这样的稳定文件名仍可能提供过期的代码。Extension.js 在开发期会在文件名后追加一段短的构建哈希(例如 content-0.abcd1234.js)。每次重新构建都会产生一个新 URL,从而绕过缓存。生产构建则使用干净的文件名。在 extension.config.*commands.dev 下设置 hashContentScripts: false 可以关闭它,保留稳定的开发期文件名。同名的顶层键会被忽略。

3) 需要重启(开发服务器)

当扩展入口的引用发生变化(而不仅仅是模块内容)时,Extension.js 会报告需要重启的诊断。这可以防止你在依赖图过期的情况下继续工作。 典型的”需要重启”场景:
  • manifest 中的脚本入口列表发生变化
  • HTML 入口的脚本/样式引用发生变化
  • watch 模式下 pages/ / scripts/ 的文件集合发生变化(尤其是删除)

行为矩阵

开发期运行时是如何注入的

重载插件会分五个注入步骤为你的构建加装,然后执行清理:
  1. 从无法承载 dev 服务器运行时的 content-script chunk 中剥离该运行时。
  2. 在 background 与 content-script 入口上建立重载策略。
  3. 注入 service-worker 的脚本重放垫片,使 /scripts/* 的注入在修改后重新执行。
  4. 注入 bridge producer,让 background 把控制台输出转发到控制通道。
  5. 注入 bridge relay,让 content-script 的控制台输出到达同一个通道。
之后会有一个清理步骤管理 hot/。热更新 chunk 是从扩展源上的磁盘获取的,所以过期的世代会在最终交付物里堆积。Extension.js 会保留当前世代以及上一个世代(供进行中的请求使用),并在每次编译后删除其余的。 整条流水线只在开发期生效。在生产构建中,以及当你传入 --no-reload 时,它不做任何事。

重载 manifest 之外的脚本与 HTML

pages/scripts/ 与 manifest 声明的资产采用同样的重载策略。
  • 现有模块更新可以走热更新路径。
  • 入口集合变化(增删或引用图变化)可能需要重启。
示例:
Extension.js 会识别 /pages/scripts 这两个文件夹用于热重载,并把每个条目当作一个可独立重载的页面或脚本。
你通过 chrome.scripting.executeScript/scripts/* 动态注入的脚本,会在文件变更时被重放。当你修改 /scripts/ 下的某个文件时,Extension.js 会在同一个 tab 上重新运行同一次注入,并卸载先前的挂载——因此动态注入的脚本可以像声明式 content_scripts 那样实时更新,而不会在你手动重新触发调用之前留下过期的 DOM。这是开发期的便利功能。

最佳实践

  • 在活跃开发会话期间保持入口引用稳定,以最大化 HMR 的命中率。
  • 集中编辑 manifest.json 与 locale,避免反复触发完整的扩展重载。
  • pages/scripts/ 用于 manifest 之外的资产,当文件集合或入口接线变化时再重启。
  • 把”需要重启”的诊断当作有意为之的安全检查,而不是临时警告。

下一步