TL;DR:你应该选哪个?
如果以下情况,选 Extension.js……
- 你希望
manifest.json作为唯一事实来源,而不是从文件名生成。 - 你希望 CLI 替你启动浏览器并加载扩展。
- 你要从同一棵代码树面向 Chrome、Edge、Firefox 和 Safari,并得到按浏览器划分的
dist/输出。 - 你想要一个仍在持续发版的打包器,以及助手可读的文档:文档 MCP 端点和
llms.txt(详情)。
如果以下情况,选 Plasmo……
- 你更喜欢 文件系统约定(
popup.tsx、contents/)而不是显式的 manifest。 - 你依赖 CSUI,它会替你把 React、Svelte 或 Vue 组件挂载进页面里的 shadow root。
- 你在用
@plasmohq/storage和@plasmohq/messaging,并且你的扩展在锁定的工具链上仍然正常工作。
一览
心智模型
Extension.js 贴近平台。 你编写manifest.json 并引用真实文件。CLI 负责编译、按浏览器过滤并打包发布。如果你已经理解一个浏览器扩展是怎样组织的,框架不会挡你的路。
Plasmo 抽象了平台。 一个名为 popup.tsx 的文件就成为 popup。contents/ 下的文件成为 content script,它的 matches 来自导出的 config 对象。Plasmo 自己的文档把它描述为“浏览器扩展界的 Next.js”。manifest 在幕后由你的源文件和 package.json 里的 manifest 字段生成。
两种方式没有绝对的好坏。选择取决于你想 看见 自己的 manifest,还是 声明 自己的 manifest。
CLI 体验
Extension.js
extension dev 在临时 profile 上启动浏览器并加载构建。参数可以是本地路径、GitHub URL 或 ZIP 压缩包。参见立即开始。
Plasmo
plasmo dev 写出 build/chrome-mv3-dev 并启动一个实时重载服务器。把那个文件夹加载进浏览器是手动步骤:Plasmo 文档写着“我们计划将来把它自动化”。每一对浏览器与 manifest 版本对应一个 --target 值。
跨浏览器策略
两个框架都把一套代码发到多个浏览器,但机制不同:- Extension.js 在单一
manifest.json里使用浏览器前缀 manifest 字段(chrome:、firefox:、gecko:等)。无前缀的键处处生效,有前缀的键只落到匹配的构建里。一次--browser=chrome,firefox运行就写出dist/chrome和dist/firefox。 - Plasmo 每次运行只构建一个目标。浏览器差异放在环境变量里:一个
.env.firefox文件、代码里的process.env.PLASMO_BROWSER,以及manifest覆盖里的环境占位符。解析不到值的占位符会把该字段从生成的 manifest 里移除。
chrome-mv3、firefox-mv2 和实验性的 firefox-mv3。它的 FAQ 说 Edge、Brave 和 Opera 因为是 Chromium 所以“应该能用”,Safari 则需要 safari-mv3 目标再手动运行 Apple 的转换器。Extension.js 把这些浏览器每一个都列为 --browser 的取值,而且 Safari 构建会替你运行转换器和 xcodebuild。
Plasmo 领先的地方
迁移之前先坦诚面对这些:- CSUI。 从 content script 导出一个 React、Svelte 3 或 Vue 3 组件,Plasmo 就把它挂载到 shadow root 里,与宿主页面的样式隔离。在 Extension.js 里,容器和 shadow root 由你自己写,见 Content scripts。
- 从仓库直接提交商店。 Plasmo 文档提供了一个 GitHub Action,Browser Platform Publisher,它读取
keys.jsonsecret 并上传到各商店。Extension.js 负责构建压缩包(为商店上传打包扩展)。上传则交给你的 CI 对接各商店的 API。extension publish命令生成的是 extension.dev 上的分享链接,不是商店提交。 - 自带辅助库。
@plasmohq/storage和@plasmohq/messaging封装了chrome.storage和chrome.runtime消息传递。Extension.js 没有对应的包。你直接调用浏览器 API,这也是迁移之后@plasmohq/storage仍能正常工作的原因。
维护状态
做决定之前自己核对这些信号。以下数值来自 2026 年 10 月 5 日的 npm 和 GitHub API。
Plasmo 仍然能安装、仍然能构建。下载量居高不下是因为现有项目一直锁定着它。它已经超过十六个月没有发布新版本,
main 上也没有新提交。如果你的扩展今天还能用,你不需要迁移。如果你要开始一个新扩展,或者需要一个仍在接收更新的打包器,请继续往下读。
迁移路径
如果你已经在用 Plasmo 并想评估 Extension.js,典型的迁移涉及四件事:- 手写一个
manifest.json,把每个约定文件映射成 manifest 条目,并把package.json里的manifest字段合并进去。 - 把 content script 的
matches从导出的PlasmoCSConfig移到 manifest 的content_scripts里。 - 把
PLASMO_PUBLIC_*重命名为EXTENSION_PUBLIC_*。 - 用
extension dev和extension build --zip替换plasmo dev、plasmo build和plasmo package。
chrome.* 调用无需改动即可照搬。完整的分步指南,包括约定到 manifest 的对照表和 CSUI 的替代方案,见从 Plasmo 迁移。
何时选择 Extension.js
- 你希望 manifest 作为事实来源,而不是生成出来的。
- 你希望 CLI 替你启动浏览器并加载扩展。
- 你要用一棵代码树、一条命令面向 Chrome、Edge、Firefox 和 Safari。
- 你想要一个仍在持续发版的打包器。
- 你想要给助手用的文档 MCP 端点和
llms.txt。
何时选择 Plasmo
- 你更喜欢文件系统约定而不是显式的 manifest。
- 你依赖 CSUI 的锚点以及它替你完成的 shadow root 挂载。
- 你已经通过 Browser Platform Publisher 发布,并且锁定的工具链仍然能构建。

