浏览器插件开发实战
- [1] 入门DEMO
- 一、创建项目
- 二、创建manifest.json
- 三、加载插件
- 四、配置 service-worker.js
- 五、以书签管理器插件为例
- manifest.json
- popup.html
- popup.js
- 查看效果
- [2] Vue项目改造成插件
- 一、复习Vue项目的结构
- 二、删除、添加个别文件
- 三、重写build
- [3] 高级开发
- 一、脚本通信
Google官方浏览器插件中文文档:https://developer.chrome.com/docs/extensions/reference?hl=zh-cn
Google官方浏览器插件示例代码仓:https://github.com/GoogleChrome/chrome-extensions-samples/tree/main
[1] 入门DEMO
一个最简单的Hello World级别的插件项目,最好要有三个文件:
1. manifest.json
2. service-worker.js
其中,manifest.json文件是插件程序说明文档,也是描述入口设置文档;service-worker.js是全局的js文件。接下来我们说明一下开发过程
一、创建项目
创建目录后,进入该目录路径
mkdir plugin_demo
cd plugin_demo
创建一个资源目录
mkdir icons
拖入你的插件图标,官方通常推荐是16x16, 32x32, 48x48, 128x128四个格式,我放了一个48*48的就够用了。
二、创建manifest.json
根目录下创建一个manifest.json主入口文件
touch manifest.json
然后编辑插件基本信息信息
{"manifest_version": 3, # 主程序api版本,这个只设置为3 2已经废弃"name": "名字", # 插件名"description": "description", # 插件描述"version": "1.0", # 插件版本"icons": { # 声明图标"16": "icons/16.png","48": "icons/48.png","128": "icons/128.png"}
}
基本信息配好后,即使是这一个文件,其实也已经可以加载插件到chrome里了。
三、加载插件
1. **chrome浏览器输入: **chrome://extensions/
2. 选中加载已解压的扩展程序
3. 选择你的项目目录
4. 查看你的插件如下:
5. 修改刷新 如果你文件有改动,通过4底部的刷新按钮,刷新加载文件观看变化。
至此,已经完成插件的初步加载过程。
四、配置 service-worker.js
如果说manifest.json是主入口文件,那么service-worker.js就像是前端项目里app.js级别的全局文件。
先在 manifest.json 配置:
{..."background": {"service_worker": "service-worker.js"}
}
然后创建与manifest.json同级的文件service-worker.js,内容为:
chrome.runtime.onInstalled.addListener(function () {console.log("插件已被安装");
})
以上就是一个demo级别的浏览器插件所需的文件。manifest.json文件里面具有丰富的配置,常用的如点击、内嵌面板、权限配置需要自行去查看官方文档。
五、以书签管理器插件为例
以一个简单的书签管理器插件为例,展示一个demo级别的插件。插件项目共有三个文件:
manifest.json
首先创建一个manifest.json文件。
{"manifest_version": 3,"name": "Bookmark Viewer","version": "1.0","description": "Uses the chrome.bookmarks API to search through, add, and delete bookmarks from the user's bookmark tree.","action": {"default_popup": "popup.html"},"permissions": ["bookmarks"]
}
action表示点击事件,即在浏览器里面点击了插件图标会如何。这里设置的default_popup表示点击之后弹出popup.html页面。
permissions是向浏览器声明要使用到的权限,这里会用到书签相关的操作,所以声明bookmarks。
popup.html
然后创建弹出给用户看的前端页面popup.html。
<!doctype html>
<html><meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"><head><title>Bookmark Viewer</title><script src="popup.js" type="module"></script></head><body><button id="addButton">添加书签</button><button id="removeButton">移除书签</button><ul id="bookmarkList"></ul></body>
</html>
popup.js
最后编写前端页面绑定的js,注意popup.js与全局service-worker.js是不一样的。
chrome.bookmarks.getTree((tree) => {const bookmarkList = document.getElementById('bookmarkList');displayBookmarks(tree[0].children, bookmarkList);
});// Recursively display the bookmarks
function displayBookmarks(nodes, parentNode) {for (const node of nodes) {// If the node is a bookmark, create a list item and append it to the parent nodeif (node.url) {const listItem = document.createElement('li');listItem.textContent = node.title;parentNode.appendChild(listItem);}// If the node has children, recursively display themif (node.children) {const sublist = document.createElement('ul');parentNode.appendChild(sublist);displayBookmarks(node.children, sublist);}}
}// Add a bookmark for www.google.com
function addBookmark() {chrome.bookmarks.create({parentId: '1',title: 'Google',url: 'https://www.google.com'},() => {console.log('Bookmark added');location.reload(); // Refresh the popup});
}// Remove the bookmark for www.google.com
function removeBookmark() {chrome.bookmarks.search({ url: 'https://www.google.com/' }, (results) => {for (const result of results) {if (result.url === 'https://www.google.com/') {chrome.bookmarks.remove(result.id, () => {});}}location.reload();});
}// Add click event listeners to the buttons
document.getElementById('addButton').addEventListener('click', addBookmark);
document.getElementById('removeButton').addEventListener('click', removeBookmark);
查看效果
1. **chrome浏览器输入: **chrome://extensions/
2. 选中加载已解压的扩展程序
3. 选择本项目目录
4. 查看插件如下:
5. 点击浏览器右上方的插件按钮,即可看到本机的书签
[2] Vue项目改造成插件
为什么要用Vue开发Chrome插件?个人主要是回到自己熟悉的模式,提高效率。我们总不能用原生JS手撸插件吧。
Vue项目改造成插件的主要原理: 改造配置文件,这样npm run build的时候,生成的内容是chrome插件结构。同时根据dist结构,配置maifest.json。
一、复习Vue项目的结构
对于一个常规的Vue2、Vue3的项目,它的结构一般是:
./project
├── public
│ ├── favicon.ico
│ └── index.html
├── src
├── package.json
├── package-lock.json
├── jsconfig.json
├── babel.config.js
├── vue.config.js
└── README.md
打包(npm run build)之后的dist文件夹结构为:
./dist
├── css
├── js
├── public
├── favicon.ico
└── index.html
可以看到public目录下的内容,被原封不动的搬到dist目录下。
而src下的vue组件和main.js, 则被编译成js和css文件,分别存储到js和css下。
由于我们开发的是chrome插件,可以把不渲染的文件放到public目录下,把渲染源文件放到src下。
另外在public下,创建一个manifest.json文件即可。
把不编译的js,放到public的好处是: 对于chrome api,我们可以直接跳过编译。直接使用chrome.xxx的形式。
二、删除、添加个别文件
把Vue项目改造成插件只需要改动一点点。
第一步,把Vue项目的public文件夹里面的内容全部删除。
第二步,在Vue项目的public文件夹里添加插件必备的文件,结构如下:
./public
├── service-worker
│ └── service-worker.js # 插件后台运行js
├── manifest.json # 插件主描述文件
├── css
│ └── your.css # 自定义css 后面会和Vue项目打包的css合并到css文件夹下
├── js
│ └── your.js # 自定义js 后面会和Vue项目打包的js合并到js文件夹下
└── icons # 插件icon图片├── 48.png├── 16.png└── 128.png
第三步,在src文件夹下添加一个popup.html。这个popup就是最终打包时会使用的html,你的manifest.json得有行为(比如action)来绑定这个文件。
./src
├── ... # 业务代码
└── popup.html # 额外添加的插件关联html
html这样写
<!DOCTYPE html>
<html lang="">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>html,body,#app {height: 100%;margin: 0px;padding: 0px;}
</style>
<body>
<div id="app"></div>
<script src="js/xxx.js"></script> # 你的自定义js
</body>
</html>
三、重写build
在vue.config.js中,配置build过程,主要说明要加载的页面是popup/popup.html。
配置vue.config.js
const { defineConfig } = require('@vue/cli-service')
const pages = {}; #声明一个page集合,如果有
const chromepages=["popup"]; # 这里主要有一个popup页面
chromepages.forEach(name=>{
pages[name]={
entry:`src/main.js`, # 页面入口是popup下的main.js
template:`src/popup.html`, # popup.html
filename:`${name}.html` # 最终渲染的页面是popup.html
};
});
module.exports = {pages,productionSourceMap: false,
}
然后执行build
npm run build
生成的目录结构如下
./dist
├── service-worker
│ └── service-worker.js
├── popup.html #渲染的弹出页面
├── manifest.json 主程序入口
├── js
│ ├── popup.ff36d80a.js
│ └── chunk-vendors.1c3d3fe0.js
├── css
│ ├── popup.0b9776ec.css
│ └── your.css
└── icons├── 48.png├── 16.png└── .png
最后,直接在Googls插件页面选择加载dist文件夹即可。
[3] 高级开发
一、脚本通信
浏览器插件所涉及到的三类JS文件有:
1. service-worker.js。属于插件的全局js,背景脚本在扩展安装后就会持续运行,不会因为浏览器的标签页切换或关闭而停止。会在浏览器下一次打开后自动恢复,拥有更广的权限。
2. content.js。指的是向用户浏览的页面注入的JS文件,我们一版统称content脚本。注入content文件有很多写法,比如直接在manifest.json文件里面声明,或者在service-worker.js里面显式地写。content脚本的作用域在用户访问的页面那里,如果想和插件传递数据需要用google提供的message方法。
3. popup.js。指的是插件的html页面使用script标签引入的JS文件,它的地位是属于插件所有,作用域在插件这边,但是权限没有service-worker.js大。
因此,说脚本通信,指的是插件脚本(service-worker.js、popup.js)和content.js脚本之间的通信。
它们之间需要用message通信:
// popup.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {console.log("收到消息:", request.data);
});// content.js
chrome.runtime.sendMessage({data: 'value'}, function(response) {console.log("收到来自popup.js的回复:", response);
});