Skip to main content
为一个或多个浏览器目标生成生产环境扩展产物。 build 会以生产模式编译你的扩展,并将输出写入 dist/<browser> 对于 monorepo / 子模块项目,关于配置期的环境变量解析(优先项目根,再退回工作区根),请参见 环境变量

什么时候使用 build

  • 为 Chrome Web Store、Edge Add-ons 或 Firefox Add-ons 准备扩展包。
  • 在持续集成(CI)中跑出可复现的生产产物。
  • 在提交前验证生产打包的输出以及各浏览器目标之间的差异。

build 命令的能力

用法

build 输出

运行 build 后,Extension.js 会为所选浏览器目标生成优化过的文件。输出位于 dist/,每个目标一个子目录。每个目录都包含打包后的 JavaScript、CSS、HTML 和必要的运行时资源。
对于 TypeScript 项目,build 也会重新生成 extension-env.d.ts 环境类型声明(与 dev 写出的是同一个文件), 所以无论你之前是否运行过 dev,CI 上的 tsc --noEmit 都能保持干净。 纯 JavaScript 项目会跳过这一步。
输出结构示例:

浏览器目标矩阵

引擎目标对 build 意味着什么

build 不会启动浏览器,因此引擎目标在这里并不指向某个二进制——但它们仍会产出一个独立的产物,而不是具名目标构建的改名副本:
  • 独立的输出目录。 --browser=chromium-based 输出到 dist/chromium-based,与 devpreviewstart 在该目标下使用的目录一致——用自定义 Chromium 二进制开发的项目,构建产物路径完全对应。
  • 独立的 env 解析。 .env.chromium-based.env.chromium-based.production 优先于家族级的 .env.chromium/.env.chrome/.env.edge,且打包后的代码中 EXTENSION_BROWSER === "chromium-based"——代码与配置可以据此区分“通用 Chromium”与某个具体商店构建。
  • 独立的 manifest 前缀。 manifest.json 中的 chromium-based: 键会作为该目标最具体的匹配生效,叠加在家族级 chromium: 键之上。chrome:edge: 键不适用。
gecko-based 相对 firefox 的行为完全相同。构建不需要浏览器二进制——--chromium-binary/--gecko-binary 只对会启动浏览器的命令有意义。

参数与 flag

--author--author-mode--debug 的隐藏、已废弃别名。

Safari flag

这些 flag 只适用于 safariwebkit-based 目标。把其中任何一个和别的目标一起传入都会以错误退出,所以拼错时不会静默地什么都不做。 Safari 打包会在构建前跑一次预检。在非 macOS 主机上,build 会告警并跳过 Safari 打包步骤,但仍然会编译 bundle。在 macOS 上,如果 Xcode 缺失或损坏,则是致命错误。

共享的全局选项

也支持 全局 flag

模式覆盖

--mode 会覆盖构建的打包器模式以及 NODE_ENV。可选值为 developmentproductionnone。当你需要为 staging 或调试产出非生产 bundle 时(类似 Vite / webpack 的工作流),可以用它来对齐行为。
无效的值会以错误退出;默认值仍然是 production development 模式的构建是可以直接发布的。它保留你在 manifest 里写的 CSP 与权限,不注入任何 reload 客户端,它的 zip 里也不包含 source map(.map 文件会留在 dist/<browser> 里供你使用)。只有 extension dev 会打开 dev 检测。--zip 在任何模式下都会打包输出,而不只是 production

zip 行为

每个 zip 都落在它自己的 dist/<browser> 目录里,与解包后的输出放在一起。不带 --zip-filename 时,名称由 manifest 的 name 转小写、去掉 a-z0-9 与空格以外的所有字符、把剩下的空格换成连字符,再接上 manifest 的 version 得到。一个名为 My Extension+、版本为 1.0.0 的 manifest 会打包成 dist/chrome/my-extension-1.0.0.zip。因为名称被改写过,请从构建输出里读取实际路径,而不要用 manifest 名称自行拼接。

示例

带 zip 输出与自定义文件名的构建

在这个示例中,构建以 Edge 与 Chrome 为目标,对输出进行打包,并保存为 my-extension.zip

带 polyfill 支持的构建

在这个示例中,构建以 Chrome 与 Firefox 为目标,并在相关地方加入 polyfill 支持。

构建源代码与产物 zip

成功的构建会打印什么

在资源汇总之后,一次成功的构建会打印输出目录和它的体积, 然后是一个可以用来把构建交给别人评审的链接:
每个目标都会打印属于自己的这一对行,所以多浏览器构建会按浏览器重复打印一次。 带警告成功的构建会在这两行之上打印警告详情, 并且编译那一行会显示 compiled with warnings 而不是 compiled in 不要用这些文案来给 CI 把关。它是写给人看的,会随版本变化。 请使用退出码,或者下面的 --output json,那才是受支持的机器契约。

--output json 输出机器可读结果

--output json 会在 stdout 上打印一个 schema-1 信封,并把给人看的构建日志转到 stderr。stdout 始终可以作为一份 JSON 文档解析。
  • 成功的运行会打印一个 status: "built" 帧。它的 value 携带构建出的浏览器、解析出的模式,以及每个浏览器一份汇总。每份汇总记录输出路径、资源总量、警告文本,以及相关时的 Safari 应用标识。
  • 失败的构建会在进程以 1 退出前打印一个 ok: false 帧,其 status: "build-failed"error.code: "E_COMPILE"
每次构建还会写出 dist/extension-js/<browser>/build-summary.json。通过 shell 调用 extension build 的脚本可以从那里读取结构化的警告。请检查文件的修改时间,避免读到过期文件。

Firefox 构建的商店检查

从 4.1.18 开始,面向 Gecko 目标(firefoxgecko-based 以及各 Gecko 分支)的生产构建会在项目里装有 addons-linter 时,用它检查 dist/<browser>。这个 linter 正是 addons.mozilla.org 审核提交时运行的工具,所以这项检查能在你上传之前暴露出会被拒绝的问题。 每一条发现都以警告形式打印。构建永远不会因此失败,退出码保持为 0。先打印一行汇总,然后每条发现各占一行,带上 linter 的代码、消息和位置:
输出最多打印 20 条发现,linter 最多运行 10 秒。超过 20 条时,会有一行说明还有多少条没显示,并指向 npx addons-linter dist/firefox 查看完整报告。运行超过 10 秒的 linter 会被放弃,构建在没有这项检查的情况下继续。 落在打包了依赖的 chunk 里的发现会标注归属,因为单看文件名可能指向错误的作者。当该 chunk 里没有你自己的代码时,这一行以 - this file is bundled dependency code (react, react-dom), not yours 结尾。当该 chunk 两者混合时,以 - this file also bundles react, react-dom, so the finding may be theirs 结尾。 当没有安装 addons-linter 时,构建会为每个项目打印一行 info 并跳过检查:
安装命令会按你项目使用的包管理器来措辞。 --no-addon-lint,或在 extension.config.js 中设置 commands.build.addonLint: false,即可关闭检查。非生产模式会跳过它,因为开发产物带有仅供开发的授权,linter 会白白地标记它们。extension start 也会跳过它,因为 start 是预览构建,而不是发布构建。

面向 Opera Add-ons 的可读输出

Opera 的审核标准要求审核者能读懂代码:扩展自身的代码若被压缩或混淆会被拒绝,第三方库则可以保持压缩。因此生产模式下的 extension build --browser=opera 不做压缩,并打印一行提示:
构建会对整个产物关闭压缩,包括依赖在内,因为一个打包后的 chunk 可能把你的代码和依赖的代码混在一起。传入 --minify 可以覆盖这一默认值,也可以在 extension.config.js 中设置 commands.build.minify。同一个选项对其他目标反向生效:当审核者要求时,--no-minify 会让 Chrome 或 Firefox 构建保持可读。

最佳实践

  • 查看构建日志: 每次构建后检查日志,看是否有警告与缺失资源。
  • 优化你的 manifest:manifest.json 与每个目标浏览器都兼容。
  • 有意识地命名产物:--zip-filename 让 CI 产物命名保持稳定。
  • 逐个目标验证输出: 发布前检查每一个 dist/<browser> 目录。之后的一次 dev 会用带开发插桩的构建覆盖同一个目录,那个构建会额外加上 scriptingtabsmanagementstorage 等权限,把你的 content script 的匹配模式合并进 host_permissions,并把 hot/*extension-js-control.json 列为只对这些匹配开放的 web-accessible resources。没有 content script 的项目不会得到后两项。打包或发布前请重新运行一次 build

下一步