基于Plasmo框架开发的一款Chrome浏览器插件(chrome v3版本)——集成GPT、千问、Deepseek等目前主流的AI大模型
背景
- 之前有开发chrome 插件的的需求,鸭子赶上架做了一个粗略版的基于原生js+jq写的,由于没有用框架进行模块化开发,导致后期维护起来相当困难,一个js文件写到了一万多行,由于功能在不断迭代,基于一款好用的开源chrome v3开发框架变成了迫切需求。
- 在网上找了多款开源的框架,都没有找到合适的,基本有两个通病:文档不齐全,有反馈的bug作者没有修复,导致重构的风险增加。
- 在网站上找了好久 看到plasmo 文档相当齐全,github start十万加。框架还是相当靠谱。于是基于次框架做了一个使用的插件,和大家一起分享一下。
技术栈
Plasmo + React + Ant Design(这里要用到它的静态引入方法普通方法会丢失样式) +TS(赶项目这里ts基本就any梭哈了)
开发技术文档:
插件嵌入的方法
据我了解目前插件注入到界面的主要有三种
- 直接插入到主界面,直接注入样式会和主页界面有冲突,之前第一版就是这种情况,各种冲突。
- 通过iframe方法嵌入,虽然也能做到样式隔离,但是通讯相对比较麻烦, 和主界面做交互不方便。
- 通过shadow-root隔离注入,比较方便,也是plasmo构建时默认的方法,下面也简单介绍一下吧,开发插件先了解前奏,后面也知道所以然。
什么是 Shadow Root?
Shadow Root 是 Web Components 技术中的一个核心概念,它是 Shadow DOM(影子 DOM)的根节点。Shadow DOM 允许开发者创建封装的 DOM 子树,这些子树与主文档 DOM 隔离,从而避免样式冲突和意外的 JavaScript 干扰。简单来说,Shadow Root 是影子树的入口点,让组件内部的 HTML、CSS 和 JavaScript 独立运行。
Shadow Root 的主要特点
- 封装性:Shadow Root 内的元素不会受到外部 CSS 或 JavaScript 的影响,反之亦然。这有助于构建可复用的组件,如自定义元素(Custom Elements)。
- 作用域隔离:样式和脚本在 Shadow Root 内生效,不会泄露到外部文档。
- 性能优化:浏览器可以优化渲染,因为影子树是独立的。
- 浏览器支持:现代浏览器(如 Chrome、Firefox、Safari、Edge)都支持 Shadow DOM。IE 不支持,但可以通过 polyfill 模拟。
插件嵌入到主页界面的方法,这里选用的的是 shadow-root ,plasmo框架自动注入到界面的默认就是这个方法。
图片显示的是插件注入到界面显示的层级以及结构信息,插入到位置框架支持自定义的,具体的可以去看plasmo官方文档。
plasmo官方中文文档:plasmo官方文档
插件功能 (这里就不写插件名字了,只和大家分享开发经验)
- 插件功能包含一下几个部分: 聊天、智能体,写作,绘图、图升文部分,插件功能集成了目前市面最新的大模型deepseek ,GPT4o、千问等目前市面最流行的大模型。
先给大家看看界面:
界面的整体功能
聊天界面的:
- 聊天界面的主要集合了大模型目前流行的几个大模型deepseek ,GPT4o、千问等,这里同时也集成了基于内部的智能体部分,做一个支持切换大模型和智能体,切换列表的功能。
- 对话聊天部分,采用的是sse流式文本返回的,且支持markdown语法展示,支持化学物理公式,当然样式有借鉴其他插件的部分,本文只讨论技术实现,其他不做过多介绍,先给大家展示一下整体的功能样子。
- 插件功能支持侧边栏和固定栏展示,以及侧边栏快捷按钮操作。
项目整体目录
以上就是整个项目,目录的整体部分,目录是安装plasmo脚手架后在原有的基础上做了部分改动,细节部分可以配合plasmo官网文档配置,下面会将一些官网文档,不够详细的坑,开发过程中我觉得难点主要就是登陆授权这一部分,以及如何静态引入antdsign组件的部分,下面也会着重讲这两部分功能的实现,并且会配置代码片段,供大家参考(前端小菜鸡,写的可能不太好,大家嘴上积德)
contents界面 :重要功能主要都集中在这个文件下,也算是实现整个插件功能的入口
提示:没有这方面的基础的话建议看看chrome v3开发文档先了解一些基础,看的更明白也知道我在说什么—chrome 插件开发文档
1.getStyle方法我这里是将个人写的样式和antdesign.css 通过字符串的形式拼接的。
export const getStyle = () => {
const style = document.createElement("style")
style.textContent = contentScss + antdResetCssText
return style
}
写chrome 插件不能和react脚手架开发框架,直接导入组件使用,这种方式的话样式不生效,当然使用antdesign有部分组件使用是有问题的,需要自己手搓,或者在原有的组件上进行二次封装配置的,这个也是我前期开发比较头疼的问题,也是踩坑最多的,网上相关案例少之又少,很难受。
个人写的样式都会集中在引入在style_public.scss文件下面的,最后统一导入到getStyle方法中,直接引入到组件是不生效的如下的示例。
import React from "react"
import "./index.scss"
export default function index(props) {
const { loading } = props
return (
<div
className="loading-lsdo223d"
style={{ display: loading ? "flex" : "none" }}>
<div className="loading-content-lsdo12dsd">
示例代码
</div>
</div>
)
}
此处样式不会生效。
- 配置chrome插件根节点挂在主界面的位置
// 插入单个锚地点
export const getInlineAnchor: PlasmoGetInlineAnchor = async () => {
// 当前文档是在 iframe 中 阻止注入
if (window.self !== window.top) return null
// 当前文档不在 iframe 中允许注入
return document.querySelector("body") as HTMLElement
}
这里有个坑,不加入这段代码的话,写的插件会循环注入到主页,有iframe的引用代码里面,不仅会影响主界面加载速度,写的快捷键按钮也会显示多个,严重影响使用体验,下面示例是判断是否是主页不是主页的话则不注入chrome插件脚本。
// 当前文档是在 iframe 中 阻止注入
if (window.self !== window.top) return null
- antdesign 静态组件如何引入的问题
import AntDrawer from "antd/es/drawer"
import AntMenu from "antd/es/menu"
import AntMessage from "antd/es/message"
import AntPopover from "antd/es/popover"
import AntTooltip from "antd/es/tooltip"
安装好antdesgin包后,组件都是在antd/es/目录下的引入使用的,使用组件前需要在根节点包裹一个ConfigProvider组件,下面是做了基于组件封装的一个全局样式配置组件
import ConfigProvider from "antd/es/config-provider"
import zh_CN from "antd/es/locale/zh_CN"
import type { ReactNode } from "react"
import React from "react"
export const ThemeProvider = ({ children = null as ReactNode }) => (
<ConfigProvider
locale={zh_CN}
theme={{
components: {
Menu: {
itemSelectedBg: "#f0ebff",
itemSelectedColor: "#6841ea",
itemActiveBg: "#f0ebff",
dropdownWidth: 120,
itemHeight: 32,
algorithm: true // 启用算法
},
Dropdown:{
zIndexPopup: 21474836489,
},
Select: {
colorPrimary: "#6841ea",
zIndexPopup: 21474836489,
selectorBg: "#4f59661f",
algorithm: true, // 启用算法
borderRadius: 8
},
Input: {
colorPrimary: "#6841ea",
algorithm: true, // 启用算法
borderRadius: 8
},
Slider: {
colorPrimary: "#6841ea",
algorithm: true // 启用算法
},
Switch: {
colorPrimary: "#6841ea",
algorithm: true // 启用算法
},
Checkbox: {
colorPrimary: "#6841ea",
algorithm: true // 启用算法
},
Spin: {
colorPrimary: "#6841ea",
algorithm: true // 启用算法
},
Radio: {
colorPrimary: "#6841ea",
algorithm: true // 启用算法
},
Popover: {
borderRadius: 12
}
}
}}>
{children}
</ConfigProvider>
)
根节点嵌套后的的示例如下:
const ContentPage = () => {
return (
<Provider store={store}>
<ThemeProvider>
<StyleProvider
container={
document.querySelector("#extensions").shadowRoot
}>
<HomePage openFixedSidbar={false} />
</StyleProvider>
</ThemeProvider>
</Provider>
)
}
export default ContentPage
StyleProvider和ConfigProvider区别,详情可以看看Ant Design官网
React 中 StyleProvider 和 ConfigProvider 的区别(表格形式)
方面 | ConfigProvider | StyleProvider |
---|---|---|
主要用途 | 配置组件的全局属性和行为,如主题、语言环境、图标、动画等。 | 专门用于样式隔离和动态样式注入,防止样式冲突。 |
常见配置项 | - theme :设置全局主题- locale :设置语言环境- prefixCls :CSS 类名前缀- getPopupContainer :弹出容器- componentSize :组件大小 |
- cache :样式缓存- hashed :哈希化类名- container :样式注入容器 |
使用场景 | 应用入口处统一配置整个应用的默认设置。 | 微前端、多实例应用或动态组件加载时进行样式隔离。 |
示例代码 | jsx<br>import { ConfigProvider } from 'antd';<br><ConfigProvider locale={zhCN} theme={{ algorithm: theme.darkAlgorithm }}><br> {/* 内容 */}<br></ConfigProvider><br> |
jsx<br>import { StyleProvider } from '@ant-design/cssinjs';<br>const cache = createCache();<br><StyleProvider cache={cache}><br> {/* 内容 */}<br></StyleProvider><br> |
影响范围 | 影响组件的行为和样式属性,但不直接处理样式隔离。 | 专注于样式管理,不涉及组件的行为配置。 |
依赖库 | 内置于 Ant Design 库。 | 来自 @ant-design/cssinjs,通常与 ConfigProvider 结合使用。 |
使用频率 | 几乎所有 Ant Design 应用都需要。 | 主要在高级场景(如微前端)中使用。 |
登陆部分 后续完善…, 码字不容易,收藏加关注,后续一一更新,有需要讨论的可以后台私信,和大家一起进步,文章可能逻辑不够清晰,写的不够好,有问题的话可以在评论区留言反馈哦。
更多推荐
所有评论(0)