背景
封装了一些浏览器插件自动化中常用的组件,都在 Github - chrome-extension-tools 仓库里。
我是基于 vitesse-lite 模板进行二次封装: demo,有兴趣的朋友可以下载跑一下。
以下内容是基于你了解浏览器插件相关的概念,如果是第一次尝试,可以看下 官网文档。
使用场景
- 自动化执行网页操作
- 获取网页应用的数据
功能点
- 消息通信:简化 Background、Content Script 和 Side Panel 之间的消息传递
- 工作流自动化:实现复杂业务流程的自动化,支持多层级任务定义、循环和重新执行功能
- 请求捕获:获取页面的请求
- 日志模块:统一日志定义,方便后续的拓展
- 类型支持:完整的 TypeScript 类型定义
如何使用
消息通信
目前有很多相关的封装,但这块消息通信的复杂度并不高,为了方便和更适配我的写法,所以我自己重新封装了消息通信的功能。
封装 Chrome Extension 的消息方法,统一 Background, Content Script 和 Side Panel 的消息通信:
- Background(Service) -> sv
- Content Script -> cs
- popup/Side Panel(后面称 Side Panel) -> sp
每个浏览器插件,只会各有一个 Background 和 Side Panel,会有多个 Content Script,所以关于 Content Script 的通信,都需要带上对应的 tabId,保证 Background(Side Panel) 可以给指定的 Content Script 发消息。
Background 发给 Content Script
Background 发给 Content Script 需要带上 tabId 才能指定发给谁:
typescript
import { sendMsgByBG, CetDestination } from 'chrome-extension-tools'
const res = await sendMsgByBG('test1', { ... }, { tabId: tabId, destination: CetDestination.cs })
Background 发给 side panel
typescript
import { sendMsgByBG, CetDestination } from 'chrome-extension-tools'
const res = await sendMsgByBG('test1', { ... }, { destination: CetDestination.sp })
具体使用,请看消息通信文档。
工作流使用
工作流模块是为实现复杂业务流程自动化设计的核心组件,以 Side Panel 为核心,通知 Content Script 或 Background 来执行相关动作。
初始化
Background:
typescript
import { initBGMsgListener, initBackground } from 'chrome-extension-tools'
// 初始化消息通知
initBGMsgListener()
// 初始化基本的消息事件
initBackground()
Content Script:
typescript
// 入口文件
import { initCSMsgListener } from 'chrome-extension-tools'
initCSMsgListener()
// 指定文件初始化,如果只有一个任务的,可以在入口文件初始化
import { initContentScriptTask } from 'chrome-extension-tools'
// 你的工作流配置
import { getTasks } from '~/tasks/index.task'
// 监听 window message 事件,将接口拦截后的数据发送给 bg 和 cs
initContentScriptRequest()
// 初始化工作流
initContentScriptTask(getTasks())
Side Panel:
typescript
import { CetActuator, CetDestination, EVENTS, onMsgInSP, sendMsgBySP } from 'chrome-extension-tools'
// 自定义 logger 对象
import { getTasks, logger } from '~/tasks/index.task'
// 监听接口事件,获取 Content Script 捕获的接口数据
onMsgInSP(EVENTS.CS2SP_GET_REQUEST, async (data) => {
console.log('data', data)
return true
})
// 获取当前 Tab 数据
async function getTab() {
const { data } = await sendMsgBySP<undefined, chrome.tabs.Tab>(EVENTS.SP2BG_GET_CURRENT_TAB, undefined, { destination: CetDestination.BG })
return data
}
// 执行工作流任务
async function start() {
logger.info('开始执行')
// 初始化工作流对象
const ins = new CetActuator(getTasks(), {
// 每次执行任务前,工作流模块会执行 getTabId 事件,返回 tabId
// @ts-ignore
getTabId: async () => {
const tab = await getTab()
return tab ? tab.id : undefined
},
taskBeforeCb: (task) => {
logger.info(`${task.name} 开始执行`)
},
taskAfterCb: (task, result) => {
logger.info(`${task.name} 执行结束 ${result ? '成功' : '失败'}`)
},
})
// 执行工作流
const result = await ins.run()
console.log(result)
logger.info('全流程结束')
}
配置任务
typescript
import type { CetWorkFlowConfigure } from 'chrome-extension-tools'
import {
CetDestination,
loopCheck,
sendMsgBySP,
} from 'chrome-extension-tools'
import { EVENT_OPEN_URL_SP2BG } from '~/constants'
export enum TaskNames {
open = '打开网页',
}
export function getTasks(): CetWorkFlowConfigure[] {
return [
{
name: TaskNames.open,
spBeforeFn: async () => {
// 通知 background 打开百度页面
sendMsgBySP(EVENT_OPEN_URL_SP2BG, { url: 'https://www.baidu.com' }, { destination: CetDestination.BG })
return {
next: true,
}
},
},
]
}
具体使用,请看文档。
接口捕获
接口拦截的配置有点长,具体可以看文档。
按文档配置后,当 Content Script 注入了脚本并刷新了一次页面,组件就会捕获到接口并将数据发送给 Background 和 Side Panel,你只需监听对应的事件即可:
typescript
import { EVENTS, handleResponseData } from 'chrome-extension-tools'
// Content Script 收到请求后,会通知给 sp
onMsgInSP(EVENTS.CS2SP_GET_REQUEST, async (data) => {
if (!data)
return
const res = {
url: data.url || '',
response: handleResponseData(data?.response),
data: handleResponseData(data?.data),
body: handleResponseData(data?.body),
headers: handleResponseData(data?.headers),
id: data.id,
}
console.log(res)
})
小结
上面所提供的核心模块,可以帮助你实现许多的自动化需求,消息通信来将各个模块串联起来,工作流帮你稳定、有序地执行业务步骤、接口拦截可以帮你获取想要的数据。
后续我会提供更多的一些例子,帮助大家能快速上手。