webpack.config.js 或 vite.config.ts:每个脚本一个入口,再加一步复制 manifest。Extension.js 把这个关系反过来:manifest.json 是事实来源,构建会从它读取每一个入口。本指南把手写配置映射到 Extension.js,并列出真实迁移中遇到的问题。如果你的项目使用 WXT、CRXJS 或 Plasmo,请从对比与迁移开始。
哪些会变,哪些不变
保持不变: 你的源文件、UI 组件、测试,以及chrome.* 或 browser.* API 调用。
会改变:
- 配置里的
entry映射不再需要。manifest 和特殊文件夹负责命名每一个入口。 - 输出目录固定为
dist/<browser>,每个浏览器目标一个目录。 - loader 和插件移入
extension.config.js。 DefinePlugin常量和.env值变成EXTENSION_PUBLIC_*变量。webpack serve或vite build --watch变成extension dev。
第 1 步:安装 Extension.js
webpack、webpack-cli、vite,以及只为旧构建接线的插件。
第 2 步:让 manifest 拥有入口
把 manifest 的每个字段指向源文件。TypeScript、JSX 和框架文件都可以直接写在那里,因为构建会编译它们并重写输出里的路径。
那一步把
manifest.json 和图标复制到输出目录的 CopyWebpackPlugin 不再需要。构建会自行输出 manifest、图标和 _locales 文件夹。
第 3 步:迁移 loader 和插件
在项目根目录创建extension.config.js。config 钩子会收到生成好的 Rspack 配置,你可以像修改 webpack 配置一样修改它。
第 4 步:更新 package.json 脚本
extension dev 会打开一个已加载扩展的浏览器,并在保存时重新加载。哪些会重载、哪些不会,见重载与 HMR。
第 5 步:迁移环境变量
把.env 文件里的变量重命名为 EXTENSION_PUBLIC_ 前缀。用 process.env.EXTENSION_PUBLIC_API_URL 或 import.meta.env.EXTENSION_PUBLIC_API_URL 读取,两种都可以。没有该前缀的变量不会进入扩展代码。参见环境变量。
第 6 步:验证
dist/chrome 作为未打包扩展加载,并与旧的输出对比。对于 Firefox,当 manifest 缺少 browser_specific_settings.gecko.data_collection_permissions 时,构建会给出警告。addons.mozilla.org 上的新扩展需要这个键,所以请在提交前加上。确切字段见多平台构建。
真实迁移中最耗时的问题
下面每一条都在迁移现有扩展时至少出现过一次。它们都不是你项目的缺陷,而且都有简短的答案。对运行时 URL 的动态 import
像import(chrome.runtime.getURL("worker.js")) 这样的代码,要求打包器解析一个只在浏览器里才存在的字符串。给它加上标记,让打包器跳过它:
public/,这样它会原样随扩展发布;如果网页会加载它,再把它列进 web_accessible_resources。
必须先于主构建存在的 bundle
有些扩展会把一个已编译的脚本当作字符串内联进另一个脚本,比如注入页面文档的脚本。内层文件必须先构建。添加一个插件,在每次构建前运行一个独立的编译器,同时挂在beforeRun 和 watchRun 钩子上:
type: "asset/source" 把 .inline/document.js 作为原始字符串导入。
自定义 loader 文件不被监听
你自己编写、并从extension.config.js 引用的 loader 不在监听范围内。编辑 loader 之后,重启 extension dev。
Pug 或其他 HTML 模板
Extension.js 不内置 Pug loader。二选一:把模板一次性渲染成静态 HTML 并提交结果,或者在config 钩子里为 .pug 文件添加一条 loader 规则。
终端里的本地化名称
如果manifest.json 把扩展命名为 __MSG_extensionName__,终端卡片会原样打印这个占位符。浏览器显示的是翻译后的名称。构建本身没有问题。
原生依赖与 npm 12
从 npm 12 起,npm install 会跳过依赖的安装脚本,除非你批准它们。像 canvas 或 pngquant-bin 这样的包会在没有二进制文件的情况下装好,构建随后以 ENOENT 失败。批准需要运行脚本的包:
package.json 的 allowScripts 下。Extension.js 自己安装缺失依赖时也带着 --ignore-scripts。当那一步也必须运行脚本时,设置 EXTENSION_ALLOW_INSTALL_SCRIPTS=true。

