过去一年,开发了两款插件并上架谷歌商店,在最初技术调研时原本想使用plasma
,考虑插件包的体积与其他未知原因,最终我还是选择了webpack5
搭建了一个基础的chrome插件
,具体可参考之前写的一篇文章#放弃plasmo,webpack5搭建了一个chrome基础插件,因为原生的插件配置也非常简单。通常的插件api使用也踩了不少坑,但从新回顾,发现plasma
解决了我当初插件业务开发中的很多问题,也真正做到了让开发者只关注业务本身就行。
按照官方教程,初始化一个插件非常简单,使用一下命令就行,按照指定命令提示,快速初始化了一个插件项目
pnpm create plasmo
我们看到初始化后的项目是下面这样的
我们发现这是一个原始的构建插件工程项目,当我们执行pnpm run dev
时,会生成一个build
文件夹,我们只需要打开chrome插件的开发者模式,添加这个build
此时我们加载完插件后,popup.html
插件就是这样的
我们修改popup.tsx
的任何一行代码时,此时会热更新到插件,无需重新加载插件,这是我之前使用webpack5
构建插件未解决的问题,因为我们次修改后,需要build,重新加载,才能生效,这种体验有点糟糕。但是plasmo
就完美解决插件热更新问题
我们看到初始化项目根目录的popup.tsx
就是我们插件打开的popup
页面,但是可以在根目录下新建一个popup
文件夹
// popup/index.tsx
import { useState } from "react"
function IndexPopup() {
const [data, setData] = useState("")
return (
<div>
<h1>公众号:Web技术学苑</h1>
</div>
)
}
export default IndexPopup
在初始化后的文件夹,我们可以使用src
来组织我们的插件,具体可以参考src,从扩展页面中可以发现,在插件中的一些页面可以组织成以下
# contents/index.tsx
# popup/index.tsx
# options/index.tsx
# newtab/index.tsx
# sidepanel/index.tsx
# devtools/index.tsx
我们发现popup
页面的样式如何控制
我们看下popup
页面,我们引入的scss
对应的index.module.scss
.app {
width: 360px;
height: 600px;
}
popup
import { useState } from "react"
import style from "./index.module.scss"
function IndexPopup() {
const [data, setData] = useState("")
return (
<div className={style["app"]}>
<h1>公众号:Web技术学苑</h1>
</div>
)
}
export default IndexPopup
看下页面结果
我们会发现plasma
天然支持css module
,真正加载插件的时候,会把scss
编译成css
插件中,popup是插件的一个气泡页面,90%
的插件都会有这个气泡,但是我们也会发现一些安装的插件会改变我们浏览器网页的内容,为什么会改变我们浏览网页的内容呢,真正影响的当前页面布局的是contents
如何在网站插入内容?我们知道插件的content.js
是可以获取到当前网页的浏览器内容的,也就是说可以操作当前网页的dom,你可以理解成加载当前网页后,chrome插件给开发者开了一个黑盒,开发者只要用户安装了这个插件,我就可以改变当前页面的dom
index.module.scss
.app {
width: 100%;
text-align: center;
padding: 10px 0;
color:red;
}
// contents/index.tsx
import React, { memo } from "react"
import style from "./index.module.scss"
interface Props {}
const Index: React.FC<Props> = (props) => {
const {} = props
return <div className={style["app"]}>hello,欢迎关注公众号Web技术学苑</div>
}
export default memo(Index)
我们发现css没有作用,但是页面内容已经插入的当前网页的html中
我们首页会发现plasma
会创建一个plasmo-csui
的webComponent
,而且插入到html
的根节点上,且样式不生效,那如何使得样式生效呢
导出默认getStyle
// contents/index.tsx
import type { PlasmoGetStyle } from "plasmo"
import React, { memo } from "react"
// 引入默认scss文件
import styleText from "data-text:./index.module.scss"
import style from "./index.module.scss"
// 引入默认样式
export const getStyle: PlasmoGetStyle = () => {
const style = document.createElement("style")
style.textContent = styleText
return style
}
interface Props {}
const Index: React.FC<Props> = (props) => {
const {} = props
return <div className={style["app"]}>hello,欢迎关注公众号Web技术学苑</div>
}
export default memo(Index)
所以样式就生效了,我们发现在contents
引入的cssmodule
并不会像在popup
一样,而是需要getStyle
这样的接口,动态插入的style
如何在指定域名中生效,现在默认是所有网站都会生效,因此我想指定网址才生效呢,我们需要导出config
即可,并配置matches
指定域名,然后重新运行项目即可
// contents/index.tsx
export const config: PlasmoCSConfig = {
matches: ["https://www.baidu.com/*"],
all_frames: true
}
...
我们发现以上的webComponent
是插入在html上的,在通常情况下,有可能实际业务中会遇到插入到页面的某个节点上,所以如何将content
的内容插入到节点上
getOverlayAnchor
,然后绑定页面具体的节点
// contents/overlayAnchor.tsx
import type {
PlasmoCSConfig,
PlasmoCSUIProps,
PlasmoGetOverlayAnchor
} from "plasmo"
import React from "react"
export const config: PlasmoCSConfig = {
matches: ["https://www.baidu.com/*"],
all_frames: true
}
export const getOverlayAnchor: PlasmoGetOverlayAnchor = () =>
document.querySelector(".quickdelete-wrap")
const ContentForQuick = () => (
<span
style={{
borderRadius: 4,
background: "red",
height: "44px",
display: "flex",
alignItems: "center"
}}>
公众号:Web技术学苑
</span>
)
export default ContentForQuick
以上就是达到我想要的目标了,不过插入的内容依旧是webCompoent
通常来讲这可能是插件内部的设置页面,我们看下如何在popup中或者content中如何打开插件中内部的页面
// options/index.tsx
import React, { memo } from "react"
interface Props {}
const Set: React.FC<Props> = (props) => {
const {} = props
return <div>我是设置页面</div>
}
export default memo(Set)
我们在popup
弹出窗口中打开
...
function IndexPopup() {
const [data, setData] = useState("")
const handleToOptionsPage = () => {
chrome.runtime.openOptionsPage()
}
return (
<div className={style["app"]}>
<h1>公众号:Web技术学苑</h1>
<div onClick={handleToOptionsPage}>go to option page</div>
</div>
)
}
因此options
页面就在弹框页面中打开了一个新的页面
这个页面会默认覆盖你当前默认打开的tab页面,你只需要在根目录新建newtab/index.tsx
即可
// newtab/index.tsx
import React, { memo } from "react"
interface Props {}
const TabsPge: React.FC<Props> = (props) => {
const {} = props
return <div>new tabs page</div>
}
export default memo(TabsPge)
当我们每新开一个tab时,默认就会插件的tab
页
我们插件内部也可以有很多内部的页面,因此,你可以在根目录新建一个tabs
目录,然后新建一个about.tsx
页面
// tabs/about.tsx
import React, { memo } from "react"
interface Props {}
const About: React.FC<Props> = (props) => {
const {} = props
return <div>about page</div>
}
export default memo(About)
我们可以在popup
弹框页面打开一个页面
import { useState } from "react"
import style from "./index.module.scss"
function IndexPopup() {
const [data, setData] = useState("")
const handleToOptionsPage = () => {
chrome.runtime.openOptionsPage()
}
const handleToNewTabPage = () => {
chrome.tabs.create({
url: `chrome-extension://${chrome.runtime.id}/newtab.html`
})
}
const handleToAboutPage = () => {
chrome.tabs.create({
url: `chrome-extension://${chrome.runtime.id}/tabs/about.html`
})
}
return (
<div className={style["app"]}>
<h1>公众号:Web技术学苑</h1>
<div onClick={handleToOptionsPage}>go to option page</div>
<div onClick={handleToNewTabPage}>go to tab page</div>
<div onClick={handleToAboutPage}>go to about page</div>
</div>
)
}
export default IndexPopup
这是chrome插件的一个新方式,可以在当前窗口打开侧边栏方式打开插件内容
import React, { memo } from "react"
interface Props {}
const Index: React.FC<Props> = (props) => {
const {} = props
return <div>this is sidepanel</div>
}
export default memo(Index)
打开sidepanel
,主要在background.js
中打开sidepanel
// background.js
chrome.action.onClicked.addListener(() =>
{
chrome.sidePanel.setOptions(
{ path: "sidepanel.html",
enabled: true,
openPanel: true
}).catch((error) => console.error("Failed to open side panel:", error));
});
plasma
构建插件的几个核心文件,比如background.js
、contents
、options
、tabs
等插件页面content.js
中使用cssModule
并插入相对指定节点扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有