Files
2026-05-09 14:55:30 +08:00

194 lines
6.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
inclusion: manual
---
# Plasmo 框架技术说明
## 1️⃣ 框架定位
Plasmo 是一个 Chrome 扩展开发框架,核心价值是:**让你用写 React 项目的方式来写 Chrome 插件**。
它帮你处理了:
- manifest.json 自动生成(不用手写)
- TypeScript/React 编译打包(内置,不用配 webpack)
- Content Script 样式隔离(Shadow DOM
- 开发时热更新(改代码自动刷新扩展)
## 2️⃣ 约定式文件结构
```
src/
├── popup.tsx # 点击插件图标弹出的小窗口
├── options.tsx # 插件设置页(右键图标→选项)
├── newtab.tsx # 覆盖浏览器新标签页
├── sidepanel.tsx # 浏览器侧边栏面板
├── background/
│ └── index.ts # 后台 Service Worker,监听事件、做中转
├── contents/
│ └── xxx.tsx / xxx.ts # 注入到目标网页里的脚本(可以有多个)
├── components/ # 自己的 UI 组件(非框架约定)
│ └── Button.tsx
└── lib/ # 工具函数(非框架约定)
└── api.ts
```
**核心规则:文件放对位置就自动生效,不需要任何注册或配置。**
| 文件 | 有就生效,没有就没这功能 |
|------|------------------------|
| `popup.tsx` | 有 → 点图标弹窗;没有 → 点图标触发 background 事件 |
| `options.tsx` | 有 → 有设置页;没有 → 没设置页 |
| `newtab.tsx` | 有 → 新标签页被接管;没有 → 正常新标签页 |
| `sidepanel.tsx` | 有 → 有浏览器侧边栏;没有 → 没有 |
| `background/index.ts` | 有 → 有后台服务;没有 → 没后台逻辑 |
| `contents/任意名.tsx` | 有几个就注入几个脚本到网页里 |
## 3️⃣ 文件后缀规则
跟目录无关,跟内容有关:
| 后缀 | 能写 HTML 标签(JSX)吗 | 用途 |
|------|------------------------|------|
| `.ts` | ❌ 不能 | 纯逻辑、工具函数、类型定义 |
| `.tsx` | ✅ 能 | 任何需要写 `<div>``<button>` 等标签的文件 |
**简单记:有尖括号标签的用 `.tsx`,没有的用 `.ts`。**
## 4️⃣ TSX vs Vue 文件对比
| | `.vue` | `.tsx` |
|--|--------|--------|
| 框架 | Vue | React |
| 结构 | template / script / style 三段式 | 全部写在一个函数里 |
| HTML 写法 | 写在 `<template>` 里,正常 HTML | 写在 JS 的 return 里,叫 JSX |
| 变量绑定 | `{{ msg }}` 双花括号 | `{msg}` 单花括号 |
| 思路 | HTML 为主,往里面插逻辑 | JS 为主,在逻辑里写 HTML |
**一句话:`.vue` 是"HTML 里面嵌 JS"`.tsx` 是"JS 里面嵌 HTML"。**
## 5️⃣ Background Service Worker
### 执行时机
- **没有固定执行时机**,完全由事件驱动
- 有事件触发时唤醒,没事干 30 秒左右自动休眠
- 全局只有一个实例
### 能做什么
- 监听插件图标点击
- 接收/转发消息(content script ↔ background
- 调用 `chrome.cookies``chrome.tabs` 等完整 Chrome API
- 定时任务(必须用 `chrome.alarms`,不能用 `setInterval`
### 不能做什么
- 不能访问 DOM(没有页面)
- 不能写持续运行的逻辑(会被休眠打断)
### 代码结构
里面基本全是事件监听器注册:
```ts
chrome.action.onClicked.addListener(...) // 图标被点击
chrome.runtime.onMessage.addListener(...) // 收到消息
chrome.runtime.onInstalled.addListener(...) // 安装/更新
```
## 6️⃣ Content Script
### 执行时机
- 页面加载时自动注入(匹配 `matches` 规则的 URL
- 默认在 `document_idle` 时机注入(DOM 解析完成后)
- 每个匹配的标签页各一个独立实例(内存不共享)
### 能做什么
- 读写目标网页的 DOM
- 往网页里注入 UI 组件(通过 Shadow DOM 隔离样式)
- 通过 `chrome.runtime.sendMessage` 与 background 通信
- 调用部分 Chrome APIstorage、runtime 等)
### 不能做什么
- 不能直接调用 `chrome.cookies`(需要通过 background 中转)
- 不能访问其他标签页
### 两种用法
| 用法 | 文件后缀 | 例子 |
|------|----------|------|
| 往网页里塞 UI | `.tsx` | 侧边栏面板、悬浮按钮 |
| 只跑逻辑不画界面 | `.ts` | 读取页面数据、监听事件 |
## 7️⃣ Content Script UIShadow DOM
当 content script 需要往网页里渲染 UI 时,Plasmo 自动用 Shadow DOM 包裹:
```
目标网页
├── 网页自己的 HTML、CSS
└── Shadow DOM(隔离墙)
└── 你的 React 组件 + 你的样式
```
- 网页的 CSS 影响不到你的组件
- 你的 CSS 也不会搞乱网页
- 通过 `getStyle` 导出函数将样式注入 Shadow DOM 内部
## 8️⃣ Manifest 配置
Plasmo 不需要手写 `manifest.json`,通过 `package.json``manifest` 字段声明权限:
```json
{
"manifest": {
"permissions": ["activeTab", "storage", "tabs", "cookies"],
"host_permissions": ["<all_urls>"],
"action": {}
}
}
```
框架会自动合并源码中的信息(如 content script 的 matches 配置)生成最终的 manifest.json。
## 9️⃣ 开发工作流
```bash
# 安装依赖
npm install
# 开发模式(热更新)
npm run dev
# 产物在 build/chrome-mv3-dev
# 生产构建
npm run build
# 产物在 build/chrome-mv3-prod
# 打包 zip(用于上架)
npm run package
```
### 加载到 Chrome
1. 打开 `chrome://extensions/`
2. 右上角开启「开发者模式」
3. 点击「加载已解压的扩展程序」
4. 选择 `build/chrome-mv3-dev` 目录
### 查看日志
| 代码位置 | 在哪看日志 |
|----------|-----------|
| Background | 扩展管理页 → 点击 "Service Worker" 链接 → 打开 DevTools |
| Content Script | 目标网页 → F12 → Console |
| Popup / SidePanel | 右键插件图标 → 审查弹出内容 |
## 🔟 环境变量
Plasmo 支持 `.env` 文件,变量必须以 `PLASMO_PUBLIC_` 前缀命名才能在代码中访问:
```env
PLASMO_PUBLIC_API_URL=http://localhost:8080/api
```
代码中通过 `process.env.PLASMO_PUBLIC_API_URL` 读取。
> 本项目未使用此机制,而是通过 `src/config.ts` 手动管理多环境配置。