Skip to main content
Extension.js 与 Plasmo 都能把现代源码编译成浏览器扩展,在你工作时重载它,并为商店打包。它们的差异在于 manifest 放在哪里、由哪个打包器干活,以及各自发布得有多活跃。本页是一份事实性的对比,让你能基于自己的项目情况而非营销话术做出选择。

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 里移除。
Plasmo 官方支持的目标是 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.json secret 并上传到各商店。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,典型的迁移涉及四件事:
  1. 手写一个 manifest.json,把每个约定文件映射成 manifest 条目,并把 package.json 里的 manifest 字段合并进去。
  2. 把 content script 的 matches 从导出的 PlasmoCSConfig 移到 manifest 的 content_scripts 里。
  3. 把 PLASMO_PUBLIC_* 重命名为 EXTENSION_PUBLIC_*。
  4. 用 extension dev 和 extension build --zip 替换 plasmo dev、plasmo build 和 plasmo package。
你的 React 组件、Tailwind 配置、测试和 chrome.* 调用无需改动即可照搬。完整的分步指南,包括约定到 manifest 的对照表和 CSUI 的替代方案,见从 Plasmo 迁移。

何时选择 Extension.js

  • 你希望 manifest 作为事实来源,而不是生成出来的。
  • 你希望 CLI 替你启动浏览器并加载扩展。
  • 你要用一棵代码树、一条命令面向 Chrome、Edge、Firefox 和 Safari。
  • 你想要一个仍在持续发版的打包器。
  • 你想要给助手用的文档 MCP 端点和 llms.txt。

何时选择 Plasmo

  • 你更喜欢文件系统约定而不是显式的 manifest。
  • 你依赖 CSUI 的锚点以及它替你完成的 shadow root 挂载。
  • 你已经通过 Browser Platform Publisher 发布,并且锁定的工具链仍然能构建。

参见