迁移到 Plasmo

迁移到 Plasmo 框架

Plasmo 浏览器扩展框架通过声明式方法简化了浏览器扩展的构建。它消除了样板代码,并提供了一个易于理解、使用和退出的基于文件的配置系统。

在本指南中,我们将引导您从任何扩展项目迁移到 Plasmo,并突出显示您需要进行的一些关键更改。

安装 Plasmo CLI

Plasmo 框架的主要驱动程序是 Plasmo CLI。这是一个 Node.js 包,包含编译器、打包器、开发服务器和为浏览器扩展量身定制的打包器:

pnpm install plasmo

要启动开发服务器,请运行 plasmo dev。要构建扩展,请运行 plasmo build。要打包扩展,请运行 plasmo package

manifest.json

Plasmo 将 manifest.json 合并到 package.json 中,并抽象掉最基本的属性:

Manifest 字段抽象化
icons自动生成带有 assets 目录中的 icon.png 文件
action, browser_actionspopup.tsx
options_uioptions.tsx
content_scriptscontents/*.{ts,tsx}, content.ts, content.tsx
backgroundbackground.ts
sandboxsandbox.tsx, 沙盒页面
manifest_version--target 构建标志设置,默认为 3
versionpackage.json 中的 version 字段设置
namepackage.json 中的 displayName 字段设置
descriptionpackage.json 中的 description 字段设置
authorpackage.json 中的 author 字段设置
homepage_urlpackage.json 中的 homepage 字段设置

Plasmo 在 package.jsonmanifest.json 之间集中常见的元数据,并自动解析任何静态文件引用(如操作、后台、内容脚本等)。

这使您可以专注于重要的元数据,例如名称、描述、OAuth、declarative_net_request 等。

此外,它使框架能够提供更强大的功能,例如:

弹出窗口、选项、新标签页

Plasmo 去除了手动挂载 React/Svelte/Vue 组件的需求。

在一个非 Plasmo 扩展项目中,为了挂载一个 React 组件,您需要创建一个 index.html 模板和相关的 JavaScript 代码:

popup.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>弹出窗口</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="popup.js"></script>
  </body>
</html>
popup.jsx
import { createRoot } from "react"
 
import Popup from "./core/popup"
 
const root = document.getElementById("root")
createRoot(root).render(<Popup />)

如果您想添加 TypeScript、LESS 或 SCSS,则需要使用 Webpack、Parcel 或 ESBuild,并设置额外的插件和加载器。

使用 Plasmo 框架,这变得更加简单。只需在源代码目录中添加一个 popup.tsxoptions.tsx 文件,并导出默认的 React 组件。

Plasmo 会处理其余的工作:

popup.tsx
import Popup from "./core/popup"
 
export default Popup

Plasmo 内置支持 CSS、SCSS、LESS、CSS Modules 和 PostCSS 插件。

例如,如果您想使用 SCSS,只需在您的 React 组件中导入 SCSS 文件:

popup.tsx
import Popup from "./core/popup"
 
import "./popup.scss"
 
export default Popup

您可以以这种方式挂载 React 组件用于选项页面、新标签页、沙盒页面和任何其他自定义页面

自定义页面

在非 Plasmo 扩展项目中,创建自定义页面通常需要额外的 HTML 模板和关联的 JavaScript 代码:

tabs/custom.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>自定义页面</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="./custom.js"></script>
  </body>
</html>
tabs/custom.js
import { createRoot } from "react"
 
import CustomPage from "./core/custom-page"
 
const root = document.getElementById("root")
createRoot(CustomPage).render(<PopupApp />)

使用 Plasmo,您可以使用内置的标签页功能轻松创建自定义页面。在源代码目录中添加一个 tabs 文件夹,并将您的自定义页面放在那里,使用 .tsx 文件:

tabs/custom.tsx
import Hello from "./core/hello"
 
export default Hello

该页面将在 chrome-extension://<extension-id>/tabs/custom.html 处可用。

内容脚本

在非 Plasmo 扩展项目中,您需要在 manifest.json 文件中指定内容脚本并用 JavaScript 编写它们:

manifest.json
{
  "content_scripts": [
    {
      "matches": ["https://*/*", "http://*/*"],
      "all_frames": true,
      "css": ["content.css"],
      "run_at": "document_start"
    }
  ]
}
content.js
console.log("Hello from content script!")

使用 Plasmo,您可以在名为 content.ts 的文件或名为 contents 的目录中指定内容脚本及其相应的配置 - 更多内容请参见后文!

这是 content.ts 文件的样子:

content.ts
import type { PlasmoCSConfig } from "plasmo"
 
export const config: PlasmoCSConfig = {
  matches: ["https://*/*", "http://*/*"],
  all_frames: true,
  css: ["~content.css"]
}
 
console.log("Hello from content script!")

无需在 manifest.jsoncontent.js 文件之间来回切换。附加的好处是配置是完全类型的,因此可以从您的 IDE 获得有价值的自动补全。

要添加多个内容脚本,请创建一个名为 contents 的目录并重复上述步骤。您可以随意命名此目录中的脚本。它们都将作为具有自己配置的内容脚本添加。

例如,假设您想添加一个将页面背景颜色更改为绿色的内容脚本。您可以通过在 contents 目录中创建一个名为 emerald-splash.ts 的文件来实现:

contents/emerald-splash.ts
document.body.style.backgroundColor = "green"

由于内容脚本文件未导出配置,Plasmo 将使用默认配置:

{
  "matches": ["<all_urls>"]
}

内容脚本 UI

如果要在网页中注入 React 组件,您的扩展可能有很多样板代码,创建 Shadow DOM、找到正确的元素挂载到、MutationObservers 等。

我们已经将所有这些抽象出来,以便您可以专注于构建组件,而无需担心其余部分。

例如,假设您想在网页中注入一个简单的按钮 React 组件。您可以通过在 contents 目录中创建一个名为 press-me.tsx 的文件来实现:

contents/press-me.tsx
export default function PressMeCSUI() {
  return <button>Press me</button>
}

Plasmo 将自动将此组件注入到页面中,并将其挂载到页面的根元素上。

如果要将组件注入到特定元素中,可以通过从文件中导出 getInlineAnchor 函数来实现:

contents/press-me.tsx
import type { PlasmoGetInlineAnchor } from "plasmo"
 
export const getInlineAnchor: PlasmoGetInlineAnchor = async () =>
  document.querySelector("#pricing")

通过返回一个 Element,Plasmo 将组件挂载到该元素旁边。您可以完全自定义挂载行为、组件渲染方式等。

此功能称为内容脚本 UI。要了解更多关于其 API 和工作原理,请查看技术文档中的生命周期

您还可以指定组件相对于要挂载的元素的插入位置:

contents/press-me.tsx
import type { PlasmoGetInlineAnchor } from "plasmo"
 
export const getInlineAnchor: PlasmoGetInlineAnchor = async () => ({
      element: document.querySelector("#pricing"),
      insertPosition: "afterend"
})

后台服务工作者

在非 Plasmo 项目中,创建后台服务工作者需要在 manifest.json 文件中指定 background 属性并用 JavaScript 编写服务工作者代码:

manifest.json
{
  "background": {
    "service_worker": "background.js"
  }
}
background.js
console.log("Hello from BGSW!")

在 Plasmo 中,您通过创建一个名为 background.ts 的文件来指定后台服务工作者:

background.ts
console.log("Hello from BGSW!")

您可以导入任何针对标准服务工作者运行时的模块到 background.ts 中。例如,您可以添加 bip39 模块:

background.ts
import { generateMnemonic } from "bip39"
 
console.log(
  "Live now; make now always the most precious time. Now will never come again."
)
console.log(generateMnemonic())

Plasmo 将自动打包 background.ts 文件并将其作为后台服务工作者添加到 manifest.json 文件中。

环境变量

如果您当前正在使用环境变量,您可以在 Plasmo 中继续使用它们。

Plasmo 框架支持开箱即用的环境变量,无需额外设置。

退出 Plasmo

Plasmo 框架的抽象理念是去除最常见的配置和样板代码。这使得开发人员可以在更高的抽象层工作——他们选择的 UI 库/框架,例如 React、Vue 和 Svelte。这是创建更强大和美丽的扩展的路径。

退出 Plasmo 非常简单,只需从您的 package.json 文件中删除 plasmo 依赖项并将您的组件移至自定义设置即可。这是因为 Plasmo 生成的所有胶水代码都在框架编译器和打包器层注入,从而使您的功能代码极具可移植性。

您还可以根据需要尽可能多地使用 Plasmo。所有 chrome API 都可用,您可以直接在功能代码中使用它们。例如,您可以直接使用 chrome.runtime.messaging API 而不是使用messaging API。内容脚本和扩展页面也是如此。