Skip to main content
无需脱离 Extension.js 的工作流即可自定义打包行为。 不必 fork 默认配置,就能解决自定义打包器需求。直接添加 loader(文件类型转换)、plugin(构建期扩展) 与 alias(导入快捷方式)。Extension.js 使用 Rspack(基于 Rust 的 JavaScript 打包器 @rspack/core) 构建,你可以直接扩展生成的配置。

工作原理

在项目根目录创建以下任一文件:
  • extension.config.js
  • extension.config.mjs
  • extension.config.cjs
config 键给生成的打包器配置打补丁。

config 能力

方式 1:函数钩子(推荐)

方式 2:对象合并

config 也可以是一个对象,Extension.js 会把它合并到基础配置之上。

Rspack 优先,webpack 兼容

Extension.js 原生使用 Rspack,但你仍可以使用大部分 webpack 生态。
  • 配置类型继承自 @rspack/coreConfiguration
  • 许多 webpack loader/plugin 可以通过兼容层工作。
  • 部分 webpack 内部 API/插件与 Rspack 并非完全 1:1 兼容。
使用 Rspack 原生插件的示例:

在多个入口之间共享模块

Extension.js 只拆分 HTML 页面。默认的 optimization.splitChunks 会给页面两个稳定的同级文件:shared/framework.js 存放 UI 框架的运行时,shared/commons.js 存放被两个或更多页面导入的任何模块。框架分组覆盖 React、Preact、Vue、Svelte 与 Lit。这两个名字都不带哈希,所以 manifest 条目或公共资源可以一直指向它们。 其他每个界面都只保留一个文件。manifest 为 background worker、content script 或注入脚本各指定一个脚本,这些界面永远不会加载同级文件。 这就是为什么在页面与 content script 之间共享模块仍然需要 import()。Rspack 会为它输出一个 chunk,每个调用方按需从扩展自身的 origin 获取这个 chunk。cacheGroup 可以给这个 chunk 一个稳定的名字:
这样配置后,从弹出层和选项页分别执行 await import("../shared/big") 都会解析到同一个输出文件 shared.js。请把 chunks 保持为 "async"。同步拆分会把代码移出入口文件,但输出的 HTML 和 manifest 只引用该入口文件,页面永远不会加载被拆出的 chunk。service worker 不能使用动态 import(),会保留自己的一份模块副本。content script 也可以共享这个 chunk,但必须通过 web_accessible_resources 暴露该文件,并通过 chrome.runtime.getURL 导入。这两条规则参见懒加载

何时使用

  • 为项目特有的文件类型添加自定义 loader/规则。
  • 为编译期转换与诊断添加插件。
  • 覆盖 Extension.js 一等公民选项未暴露的 resolve alias 与模块行为。

最佳实践

  • 优先使用一等公民选项:在低层级打包器覆盖之前,先用 browser / commands 配置键。
  • 尽量少打补丁:只修改你需要的部分,然后返回配置。
  • 保持插件对 Rspack 友好:尽量使用 Rspack 原生插件。
  • 在所有目标上验证:配置变更后,在你的浏览器矩阵上测试 devstartpreviewbuild

下一步