浏览器插件开发-plasmo
Plasmo 是专为现代浏览器扩展开发设计的框架,能极大简化 Manifest V3 扩展的开发流程,解决原生开发中的配置繁琐、打包复杂等问题 零配置开箱即用:内置 Webpack/Vite 打包

浏览器插件开发-plasmo

发布时间:2025-12-27 (2025-12-27)

Plasmo 是专为现代浏览器扩展开发设计的框架,能极大简化 Manifest V3 扩展的开发流程,解决原生开发中的配置繁琐、打包复杂等问题

  1. 零配置开箱即用:内置 Webpack/Vite 打包、TypeScript 支持、热重载,无需手动配置 manifest.json
  2. 简化 Service Worker 开发:统一的背景脚本(Background)开发体验,无需关注 SW 生命周期细节;
  3. 原生支持 React/Vue:无缝集成前端框架,开发弹窗、选项页更高效;
  4. 自动处理权限 / 清单:通过代码注释或配置自动生成 manifest.json,无需手动维护;
  5. 跨浏览器兼容:一键适配 Chrome、Edge、Firefox 等主流浏览器。

创建项目

pnpm create plasmo multilingual-extensio 

这个命令默认会创建react的项目,如果要创建vue的项目,可以使用 --with-vue

pnpm create plasmo --with-vue

项目结构

我就以vue的插件项目为例,其中

popup.vue就是插件的弹窗页面

plasmo-inline.vue就是插入网页元素的内容

plasmo-overlay.vue就是浮动在网页的内容

如果需要创建service work,那么在项目根目录下创建 background.ts文件就ok了

然后要创建options,那么在项目根目录下创建一个options.vue文件就ok了

如果新创建的没出来,在插件列表页面刷新一下插件就好了

消息通信

消息通信除了可以用原生 chrome.runtime.sendMessage之外,还可以用plasmo封装的消息

使用原生消息 popup → service worker

console.log("background")
chrome.runtime.onMessage.addListener((message, sender, sendResponse)=>{
    console.log("收到消息了", message)
    sendResponse({message: "响应"})
})

popup.vue

<template>
  <div>
    <h2 class="text-center">
      Welcome to your1
      <a href="https://www.plasmo.com" target="_blank">Plasmo</a> Fengfeng!
    </h2>

    <button @click="send">发消息</button>

  </div>
</template>

<style>

.text-center {
  text-align: center;
}
</style>

<script setup lang="ts">
async function send(){
  const res = await chrome.runtime.sendMessage({type: "xxx", message: "xxx"})
  console.log("响应", res)
}
</script>

使用plasmo消息

pnpm install @plasmohq/messaging

目录结构

background
    messages
        ping.ts  // 每个消息一个文件
    index.ts
popup.vue
import type { PlasmoMessaging } from "@plasmohq/messaging"

const handler: PlasmoMessaging.MessageHandler = async (req, res) => {
    console.log("请求", req)

    res.send({
        message: "响应"
    })
}

export default handler

其他需要发送消息的,就使用sendToBackground 去发消息

<template>
  <div>
    <h2 class="text-center">
      Welcome to your1
      <a href="https://www.plasmo.com" target="_blank">Plasmo</a> Fengfeng!
    </h2>

    <button @click="send">发消息</button>

  </div>
</template>

<style>

.text-center {
  text-align: center;
}
</style>

<script setup lang="ts">
import { sendToBackground } from "@plasmohq/messaging"
async function send(){
  const resp = await sendToBackground({
    name: "ping",
    body: {
      id: 123
    }
  })
  console.log("响应", resp)
}
</script>

content script玩法

<template>
  <span className="hw-top">
    If I can have honesty, it's easier to overlook mistakes
  </span>
</template>

<script lang="ts">
import cssText from "data-text:~/contents/plasmo-overlay.css"
import type { PlasmoCSConfig, PlasmoGetStyle } from "plasmo"

export const config: PlasmoCSConfig = {
  matches: ["https://www.plasmo.com/*"]
}

const getStyle: PlasmoGetStyle = () => {
  const style = document.createElement("style")
  style.textContent = cssText
  return style
}

export default {
  plasmo: {
    getStyle
  },
  setup() {},
  mounted() {}
}
</script>

这个是默认生成的结构,template是以shadow的放入插入到页面中的

matches就是匹配规则,符合这个匹配规则的才会执行

如果我要给不同网站注入不同的js应该怎么办呢,很简单,不同的网站创建不同的vue文件

如下

如果是inline,就是将对应组件插入到页面元素的指定位置

<template>
  <span class="hw-top">
    fengfengzhidao-inline
    <button @click="xxx">点我</button>
  </span>
</template>


<style>
</style>


<script lang="ts">
import type {PlasmoCSConfig, PlasmoGetInlineAnchor, PlasmoGetStyle, PlasmoMountShadowHost} from "plasmo"

export const config: PlasmoCSConfig = {
  matches: ["https://www.fengfengzhidao.com/*"]
}

const getInlineAnchor: PlasmoGetInlineAnchor = () =>
    document.querySelector(".my_site")

const mountShadowHost: PlasmoMountShadowHost = ({ anchor, shadowHost }) => {
  anchor!.element!.insertBefore(shadowHost!, anchor!.element!.firstChild)
}

export default {
  plasmo: {
    getInlineAnchor,
    mountShadowHost,
  },
  setup() {
    function xxx(){
      // alert("我被点击了")
      console.log("xxx")
    }
    return {xxx}
  },
  mounted() {}
}
</script>