extension.config.js(或 .mjs / .cjs),并把设置应用到所有命令与打包器。
工作原理
在项目根目录(通常和package.json 同级) 添加 extension.config.js。
支持的文件名:
extension.config.jsextension.config.mjsextension.config.cjs
类型安全的配置
Extension.js 从extension 包中导出 FileConfig 类型,让编辑器可以对你的配置进行自动补全与类型检查。用 JSDoc 的 @type 标签标注导出即可 —— 它在 extension.config.js、.mjs 与 .cjs 中都能工作,且无需构建步骤:
配置文件的环境加载
extension.config.* 在 Node 中运行,应通过 process.env.* 读取值。
- 在求值
extension.config.*之前,Extension.js 会按从弱到强的顺序预加载 env 文件:.env.defaults、.env、.env.local、.env.development。每个存在的文件都会加载,而 shell 导出的变量始终优先。 - 它会先检查项目目录。
- 在 monorepo 中,如果 Extension.js 在项目本地没找到任何
.env*文件,会回退到最近的 workspace 根目录。workspace 根目录是包含pnpm-workspace.yaml的目录。 - 在配置文件中,优先使用内置的 env 预加载,而不是导入
dotenv。
浏览器配置
每个目标需要不同的浏览器默认值?使用browser:
chrome、edge、firefox、chromium、chromium-based、gecko-based、firefox-based。
常用的浏览器字段:
profile、persistProfilepreferencesbrowserFlags、excludeBrowserFlagschromiumBinary、geckoBinaryextensions(仅加载的附属扩展)
浏览器目标能力
命令配置
用commands 为每个命令定义默认值:
extensions、transpilePackages与perfBudgets在每个命令上都按从弱到强分层:顶层,然后是browser.<vendor>,然后是commands.<cmd>,最后是 CLI flag。define在同样的层上逐键合并:顶层,然后是browser.<vendor>,然后是dev、start和build上的commands.<cmd>。folders从不逐键合并。browser.<vendor>.folders替换顶层对象,dev、start和build上的commands.<cmd>.folders则同时替换这两者。commands.build.browser、commands.start.browser与commands.preview.browser决定这些命令的目标浏览器。--browserflag 仍然优先。start命令在内部会先运行build,然后preview。Extension.js 会应用commands.start中的设置,包括profile、browserFlags、startingUrl等浏览器启动选项。你也可以把构建相关的设置放进commands.build。
命令通用能力
build 命令能力
dev 命令能力
日志能力
编译期常量
用define 把常量内联进每个 bundle。Extension.js 会把每个值序列化为 JSON,所以字符串、数字、布尔值和普通对象都可以:
__APP_VERSION__ 当作一个裸标识符来读取,构建会把它替换成对应的值。在 TypeScript 项目里,每个键还会在生成的 extension-env.d.ts 中得到一条环境声明,所以 __APP_VERSION__ 会按 string 通过类型检查。
特殊文件夹的位置
用folders 移动某个特殊文件夹,或者把它关掉。路径从项目根目录解析:
- 移动后的
scripts或pages文件夹必须保留原名。Extension.js 不会读取src/injected这样的路径。 false会关掉这个文件夹。Extension.js 不再把其中的文件编译成入口,也不再复制public文件夹。- 被关掉的
scripts文件夹里、由你的代码点名的脚本(例如在chrome.scripting.executeScript({files})中)仍然会发布。Extension.js 会像编译其他文件夹里的脚本一样编译它,不加内容脚本包装。 - 被关掉的
public文件夹里的任何内容都不会发布,/icon.png这样的根路径也不再指向那里。如果 manifest 仍然点名那里的文件,构建会失败并逐一列出这些文件。如果页面或样式表引用了那里的文件,构建会为每处引用打印一条警告。请重新打开这个文件夹,或者把文件移出public/。
- 被关掉的
- 移动后的文件夹与默认文件夹的行为完全一致。移动后的
scripts文件夹里的脚本会得到内容脚本包装,并在dev中原地重载。移动后的pages文件夹里的页面会构建到同样的pages/输出。页面、样式表或 manifest 用同样的根路径(例如/logo.png)就能访问移动后的public文件夹里的文件。 - 当
public指定了路径时,Extension.js 只从那个文件夹复制。 browser.<vendor>.folders会整体替换顶层对象,commands.<cmd>.folders则同时替换这两者。两者都不会逐键合并。
Rspack 配置
需要更高级的打包器自定义?用config 给生成的 Rspack 配置打补丁。这个示例需要 4.1.31 之后的版本:在那之前,config 里的 config.module.rules 是 undefined,而 configResolved 才是能看到规则的钩子:
config 也可以是一个对象,Extension.js 会把它合并到生成的配置之上。
config 在 Extension.js 挂上它的 loader 规则之前运行。要读取或修改最终的配置,请使用 configResolved。它在每次 dev、build 或 start 运行中只执行一次,就在第一次编译之前,并收到已挂上所有 loader 规则的 Rspack 配置:
module、resolve、resolveLoader、node、optimization.minimize、optimization.minimizer,以及 Rspack 在构建开始时才读取的 output 选项,例如文件名和 environment。可以就地修改它们,也可以返回一个新的配置对象。这个钩子可以是异步的,什么都不返回的钩子会让配置保持原样。
到这时 Rspack 已经消费了其余所有键。这包括 entry、plugins、context、mode、target、devtool、externals、experiments 和 performance 这类键,minimize 与 minimizer 之外的所有 optimization 键,以及这些 output 键:path、module、library、enabledLibraryTypes、chunkFormat、chunkLoading、enabledChunkLoadingTypes、wasmLoading、enabledWasmLoadingTypes、workerChunkLoading、workerWasmLoading、workerPublicPath、pathinfo、sourceMapFilename、devtoolModuleFilenameTemplate、devtoolFallbackModuleFilenameTemplate、devtoolNamespace、bundlerInfo。对其中任何一个的修改,包括深入到值内部的修改,Extension.js 都会撤销,并打印一条按路径列出每个键的警告。请在 config 里设置它们。
钩子上下文
两个钩子都会收到第二个参数,用来说明本次运行。它带有browser(目标浏览器,与 --browser 的写法一致)、mode(development、production 或 none)和 command(dev、build、start 或 preview)。用它为某一个浏览器修改打包器,而不必读取 process.argv。下面的例子让 Firefox 的商店构建保持可读,方便审核:
extension 包为这个参数导出了 ConfigHookContext 类型。只接收一个参数的钩子仍然可以正常工作。
为某一个浏览器保留一组 locale
商店接受的语言可能少于你的_locales 文件夹所包含的语言。Extension.js 会为每个浏览器复制整个文件夹。要为某一个浏览器只发布其中一部分,请从 config 推入一个插件,删除其他 locale 的资源:
extension build --browser=edge 只会发布 _locales/en 和 _locales/de。其他所有浏览器仍保留整个文件夹。过滤器必须保留 default_locale 所指的文件夹。当它删除了那个文件夹时,构建会失败,并在错误中指出该 locale。
完整示例
最佳实践
- 把浏览器特定的值放进
browser:让命令定义专注于工作流,而不是浏览器内部细节。 - 有意识地使用顶层默认值:把共享的
extensions/transpilePackages放在根级,只在必要时覆盖。 - 优先使用
chromiumBinary/geckoBinary这类命名:与当前命令与类型接口一致。 - 保持
config钩子最小化:只添加 Extension.js 一等公民选项未覆盖的内容。

