开发浏览器插件-基于配置自动化执行

背景

封装了一些浏览器插件自动化中常用的组件,都在 Github - chrome-extension-tools 仓库里。

我是基于 vitesse-lite 模板进行二次封装: demo,有兴趣的朋友可以下载跑一下。

以下内容是基于你了解浏览器插件相关的概念,如果是第一次尝试,可以看下 官网文档

使用场景

  1. 自动化执行网页操作
  2. 获取网页应用的数据

功能点

  1. 消息通信:简化 Background、Content Script 和 Side Panel 之间的消息传递
  2. 工作流自动化:实现复杂业务流程的自动化,支持多层级任务定义、循环和重新执行功能
  3. 请求捕获:获取页面的请求
  4. 日志模块:统一日志定义,方便后续的拓展
  5. 类型支持:完整的 TypeScript 类型定义

如何使用

消息通信

目前有很多相关的封装,但这块消息通信的复杂度并不高,为了方便和更适配我的写法,所以我自己重新封装了消息通信的功能。

封装 Chrome Extension 的消息方法,统一 Background, Content Script 和 Side Panel 的消息通信:

  1. Background(Service) -> sv
  2. Content Script -> cs
  3. 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)
})

小结

上面所提供的核心模块,可以帮助你实现许多的自动化需求,消息通信来将各个模块串联起来,工作流帮你稳定、有序地执行业务步骤、接口拦截可以帮你获取想要的数据。

后续我会提供更多的一些例子,帮助大家能快速上手。

相关推荐
奔跑的web.9 小时前
TypeScript 全面详解:对象类型的语法规则
开发语言·前端·javascript·typescript·vue
江上月5139 小时前
JMeter中级指南:从数据提取到断言校验全流程掌握
java·前端·数据库
代码猎人9 小时前
forEach和map方法有哪些区别
前端
恋猫de小郭9 小时前
Google DeepMind :RAG 已死,无限上下文是伪命题?RLM 如何用“代码思维”终结 AI 的记忆焦虑
前端·flutter·ai编程
m0_471199639 小时前
【小程序】订单数据缓存 以及针对海量库存数据的 懒加载+数据分片 的具体实现方式
前端·vue.js·小程序
编程大师哥9 小时前
Java web
java·开发语言·前端
A小码哥9 小时前
Vibe Coding 提示词优化的四个实战策略
前端
Murrays9 小时前
【React】01 初识 React
前端·javascript·react.js
大喜xi9 小时前
ReactNative 使用百分比宽度时,aspectRatio 在某些情况下无法正确推断出高度,导致图片高度为 0,从而无法显示
前端
helloCat9 小时前
你的前端代码应该怎么写
前端·javascript·架构