Chrome Extension 开发解析
一、Chrome Extension 简介Chrome Extension,本质上是一个由 HTML、CSS、JavaScript 等前端技术开发的程序,就像我们平时开发的前端项目一样,它只是一个有各种资源组成的程序,被安装到浏览器后,能极大地扩展浏览器的功能。Chrome Extension 可以理解为一个独立运行在 Chrome 浏览器下的 APP,能够与打开的网页、Chrome 控制面板、第
一、Chrome Extension 简介
Chrome Extension,本质上是一个由 HTML、CSS、JavaScript 等前端技术开发的程序,就像我们平时开发的前端项目一样,它只是一个有各种资源组成的程序,被安装到浏览器后,能极大地扩展浏览器的功能。Chrome Extension 可以理解为一个独立运行在 Chrome 浏览器下的 APP,能够与打开的网页、Chrome 控制面板、第三方插件等进行通信。比如,它可以实现屏蔽广告(如 Adblock Plus)、帮助开发者进行调试开发(如 React Developers Tools)、自动更换壁纸(如 Momentum)、解决跨域问题(如 Allow CORS)、翻译网页内容等诸多功能。2009 年,Google Chrome Web Store 推出,标志着 Chrome Extension 正式进入开发者社区。此后,随着 Chrome 浏览器用户基数的增加,Chrome Extension 也在不断发展。2010 年开始稳步增长,发布了许多实用的拓展;2013 年,Chrome App 和扩展合并;2014 年,采用 Material Design 风格并增加更多 API;2016 年,Google 宣布推出 Manifest V3 计划;2021 年,Manifest V3 正式发布;2022 年持续发展,到 2024 年 Manifest V2 将会被逐步弃用。使用 Chrome Extension 可以根据个人需求自定义浏览器功能,提高工作效率,改善隐私和安全,同时也为开发者创造了创新和实用的工具。它不仅是技术的体现,还能调整用户使用浏览器的心态,让用户更加舒适、高效地浏览网页。
二、开发基础
1.基本组成
Chrome Extension 主要由以下几个部分组成:
manifest.json:这是扩展的核心配置文件,就像项目的 “说明书” 一样,详细列出了扩展的名称、版本、描述、权限等重要信息。它位于扩展的根目录,是 Chrome 浏览器识别和运行扩展的关键。例如,通过 “manifest_version” 指定清单文件的版本,目前逐渐向 Manifest V3 过渡,到 2024 年 Manifest V2 将被逐步弃用。“name” 定义扩展的名称,方便用户识别;“version” 明确扩展的版本号,便于开发者进行版本管理;“description” 提供扩展的描述,帮助用户了解其功能。此外,“icons” 属性可以设置不同尺寸的图标,适应不同的显示场景,如在扩展管理页面、安装过程以及浏览器工具栏上的显示。“browser_action” 或 “page_action” 配置项可以定义扩展在浏览器工具栏上的表现行为,包括图标、标题和点击图标时弹出的页面等。“permissions” 则用于声明扩展所需的权限,确保扩展能够正常运行并访问必要的资源。总之,manifest.json 是 Chrome Extension 不可或缺的重要组成部分。
background script:可以理解为插件运行在浏览器中的一个后台 “网站” 或脚本,与当前浏览页面无关。它通常包含对扩展很重要的浏览器事件的侦听器,处于休眠状态,直到触发事件才执行相应的逻辑。有效的后台脚本仅在需要时加载,并在空闲时卸载。例如,可以调用全部的 Chrome API,实现跨域请求、网页截屏、弹出 Chrome 通知消息等功能。在 manifest.json 文件中,通过 “background” 配置项来指定后台脚本的相关信息,如 “scripts” 属性可以指定要执行的脚本文件。
content script:是在网页上下文中运行的文件,能够读取浏览器访问的网页的详细信息,对其进行更改,并将信息传递给父级扩展。它可以操作 DOM,但是和页面其他的脚本是隔离的,访问不到其他脚本定义的变量、函数等,相当于运行在单独的沙盒里。在 manifest.json 中,通过 “content_scripts” 属性来配置内容脚本,包括匹配的域名、要执行的脚本文件以及脚本运行的时刻等。
popup:当用户点击插件图标时弹出的页面,包含 HTML、CSS 和 JavaScript 文件。它会在每次点击插件图标时重新载入,可以实现与用户的交互功能。在 manifest.json 中,通过 “browser_action” 或 “page_action” 的 “default_popup” 属性来指定弹出页面的路径。
这些组成部分相互协作,共同构成了功能强大的 Chrome Extension。
2.开发准备
开发 Chrome Extension 非常简单,仅需 Chrome 浏览器和一个带语法高亮的文本编辑器即可。首先,打开 Chrome 浏览器,在地址栏中输入 “chrome://extensions/”,进入扩展程序管理页面,然后开启开发者模式。这样就可以通过加载已解压的扩展程序来进行本地开发和调试。对于文本编辑器,可以选择 Visual Studio Code、Sublime Text 等,它们提供了丰富的插件和语法高亮功能,方便开发者编写和编辑 Chrome Extension 的代码。在开发过程中,可以利用 Chrome 浏览器提供的开发者工具来调试扩展程序,查看日志输出、检查元素等,提高开发效率。总之,开发 Chrome Extension 所需的工具简单易获取,使得开发者能够快速上手并实现各种创意功能。
三、开发步骤
1.创建 manifest
manifest.json 文件是 Chrome Extension 的核心配置文件,它定义了插件的基本属性信息和运行路径等。在创建这个文件时,我们需要明确以下几个关键部分:
manifest_version:指定清单文件的版本。目前,逐渐向 Manifest V3 过渡,到 2024 年 Manifest V2 将被逐步弃用。这个版本号的选择会影响到插件能够使用的 API 和功能。name:插件的名称,应简洁明了,方便用户识别。例如,可以根据插件的功能来命名,如 “广告拦截器”、“语法检查助手” 等。
version:插件的版本号,便于开发者进行版本管理。每次对插件进行更新时,应该相应地增加版本号,以便用户了解插件的更新情况。
description:对插件功能的简短描述,帮助用户在安装之前了解插件的用途。描述应该清晰、准确,突出插件的主要特点和优势。
icons:定义一系列图标,用于在不同的场景下显示插件的图标。可以根据需要提供不同尺寸的图标,以适应不同的显示环境。例如,可以提供 16x16、32x32、48x48 等尺寸的图标。
browser_action或page_action:配置插件在浏览器工具栏上的表现行为。可以定义图标、标题和点击图标时弹出的页面等。如果插件对在浏览器中加载的所有网页都生效,可以选择browser_action;如果只针对特定的网页生效,则可以选择page_action。
permissions:声明插件所需的权限,确保插件能够正常运行并访问必要的资源。例如,如果插件需要访问存储功能,就需要在permissions中添加 “storage” 权限。
总之,创建 manifest.json 文件是开发 Chrome Extension 的重要一步,它为插件的运行提供了基本的配置信息和权限声明。
2.加载插件
加载插件的方法非常简单。首先,在地址栏中输入 “chrome://extensions/”,进入扩展程序管理页面。然后,开启开发者模式,这将允许我们加载未经过 Chrome Web Store 审核的本地插件。接着,点击左上角的 “加载已解压的扩展程序”,并选择插件所在的目录。这样,插件就会被成功载入到 Chrome 浏览器中。
需要注意的是,插件不会热更新,每次修改代码后,需要点击扩展程序管理页面中的刷新按钮,才能载入最新的代码。此外,为了方便使用,可以将插件固定到标签栏里,这样可以快速访问插件的功能。
3.添加功能
注册 background.js,作为后台脚本初始化事件监听并设置存储初始值。
background.js 是一种后台脚本,它在插件安装或重新加载时被扫描并初始化。在这个脚本中,我们可以添加事件监听器,以响应各种浏览器事件。例如,可以在插件安装完毕后,设置一个初始值为空数组的存储字段,以便后续存储用户的访问历史。
以下是一个示例代码:
chrome.runtime.onInstalled.addListener(() => {
console.log('后台脚本运行成功!')
chrome.storage.sync.set({ history: [] });
});
这段代码在插件安装后,打印一段日志信息,并通过 storage API 设置一个初始值为空数组的存储字段。覆盖默认 popup 界面,展示用户访问历史,包括从 storage 读取历史内容并组装成 html 插入文档。为了展示用户的访问历史,我们需要覆盖默认的 popup 界面。在 manifest.json 文件中,可以通过 “action” 配置项的 “default_popup” 属性来指定弹出页面的路径。例如:
{
"action": {
"default_popup": "popup.html"
}
}
在 popup.html 文件中,可以使用 HTML、CSS 和 JavaScript 来构建用户界面。以下是一个示例代码:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="popup.css">
</head>
<body>
<div id="container">暂无浏览记录~</div>
<script src="popup.js"></script>
</body>
</html>
在 popup.js 文件中,可以从 storage 中读取历史内容,并将其组装成 html 插入到文档中。以下是一个示例代码:
chrome.storage.sync.get("history", ({ history }) => {
const contentHTML = history.length === 0? "暂无浏览记录~" : history.map((record) => {
return `<div class="item-box"><div class="item-box_time">${record.time}</div><a class="item-box_text" href="${record.url}">${record.title}</a></div>`;
}).join("");
document.querySelector('#container').innerHTML = contentHTML
});
通过内容脚本记录浏览历史,将访问页面的标题、url 和时间存储到 storage。为了记录用户的浏览历史,我们需要在内容脚本中编写记录的逻辑。在 manifest.json 文件中,可以通过 “content_scripts” 配置项来指定要注入到网页中的脚本。例如:
{
"content_scripts": [{
"matches": ["*://*/*"],
"js": ["content/index.js"]
}]
}
在 content/index.js 文件中,可以获取访问的页面的标题、url 和时间,并将其存储到 storage 中。以下是一个示例代码:
chrome.storage.sync.get("history", ({ history }) => {
console.log("history--->", history);
history.unshift({
title: document.title,
url: location.href,
time: new Date().toLocaleString(),
});
chrome.storage.sync.set({ history });
});
4.添加自定义 icon
为了让插件更加个性化,可以使用熊猫图片作为插件的 icon。首先,在插件目录中新增一个 assets 目录,并将熊猫图片命名为 icon.png 放入该目录。然后,在 manifest.json 文件中,通过 “action” 配置项的 “default_icon” 属性来指定 icon 的路径。例如:
{
"action": {
"default_icon": {
"16": "/assets/icon.png"
}
}
}
这样,插件就会使用熊猫图片作为 icon 显示在浏览器工具栏上。
四、开发注意事项
1.chrome 传递消息
chrome 传递消息的 API 在不同版本有变化,需进行兼容处理。在开发 Chrome Extension 的过程中,需要注意 chrome 传递消息的 API 在不同版本有变化。为了确保插件在不同版本的 Chrome 浏览器上都能正常运行,可以进行兼容处理。以下是一段兼容处理的代码示例:
function compatibleChrome() {
if (!chrome.runtime) {
// Chrome 20 - 21
chrome.runtime = chrome.extension;
} else if (!chrome.runtime.onMessage) {
// Chrome 22 - 25
chrome.runtime.onMessage = chrome.extension.onMessage;
chrome.runtime.sendMessage = chrome.extension.sendMessage;
chrome.runtime.onConnect = chrome.extension.onConnect;
chrome.runtime.connect = chrome.extension.connect;
}
}
通过这段代码,可以在不同版本的 Chrome 浏览器中实现对传递消息 API 的兼容,确保插件能够正常接收和发送消息。
2.本地存储
本地存储 Localstorage 只能设置字符串,json 需转成字符串形式,配置 background.js 可随时读取本地数据。在使用 Chrome Extension 的本地存储 Localstorage 时,需要注意它只能设置字符串类型的值。如果要存储 JSON 对象,需要将其转换为字符串形式。例如:
// 设置 JSON 对象到 Localstorage
const jsonObject = { key: 'value' };
window.localStorage.setItem('domain:key', JSON.stringify(jsonObject));
// 从 Localstorage 获取 JSON 对象
const storedValue = window.localStorage.getItem('domain:key');
const parsedObject = JSON.parse(storedValue);
此外,如果要随时读取本地数据,可以在 manifest.json 中配置 background.js。例如:
{
"background": {
"scripts": ["js/background.js"]
}
}
这样,content_script 里面的代码就可以随时读取 Localstorage 里面的数据,避免了需要 Browser_action 的 popup.html 一直打开的情况。通过这种方式,可以更加方便地管理和使用插件的本地存储数据。
五、开发案例展示
1.git 提交的 emoji 速查工具
此工具由一个manifest.json文件、html文件和一个png图片文件组成。功能非常简单,点击弹出一个html页面,以达到速查的目的,html里可以替换成任何想要的内容。以下是manifest.json的基本配置:
{
"manifest_version":2,
"name":"git commit emoji速查",
"description":"git commit emoji对照表",
"version":"1.0.0",
"browser_action":{
"default_icon":"icon.png",
"default_title":"这是一个 git commit emoji 速查的Chrome插件",
"default_popup":"popup.html"
}
}
2.自定义右键菜单
鼠标右键的菜单使用chrome.contextMenus实现。例如:
chrome.contextMenus.create({id: 'page',title: '测试右键菜单'});
chrome.contextMenus.create({id: 'baidu-search',title: '使用百度搜索:%s',contexts: ['selection']});
chrome.contextMenus.onClicked.addListener(function(info, tab) {
switch(info.menuItemId){
case'baidu-search':
chrome.tabs.create({url: 'https://www.baidu.com/s?ie=utf-8&wd=' + encodeURI(info.selectionText)});
break;
}
});
3.覆盖特定页面
在manifest.json里添加chrome_url_overrides,可以被替换的只有新标签页newtab、历史记录页history、书签页bookmarks这三个选项,但是一个插件只能重写一个默认页。例如:
"chrome_url_overrides":{
"newtab":"newtab.html"
}
4.开发者工具自定义面板
通过chrome.devtools API来实现自定义开发者工具面板,大家熟悉的 vue 插件就是通过这种方式实现。例如:
// 几个参数依次为:panel标题、图标(其实设置了也没地方显示)、要加载的页面、加载成功后的回调
chrome.devtools.panels.create("TestPanel", "", "devtools.html", function(panel) {
console.log("自定义面板创建成功!", panel);
});
// 创建自定义侧边栏
chrome.devtools.panels.elements.createSidebarPane("Images", function(sidebar) {
sidebar.setExpression('document.querySelectorAll("img")', 'All Images');
});
5.选项页
选项页实际上是指插件的详细信息介绍,配置在manifest.json里的options_ui。例如:
"options_ui":{
"page":"options.html",
"browser_style":true
}
6.搜索建议
在manifest.json里配置触发关键词,配置后再地址栏输入关键词后按空格键触发插件搜索建议。例如:
"omnibox":{
"keyword":"go"
}
chrome.omnibox.onInputChanged.addListener((text, suggest) => {
console.log('inputChanged: ' + text);
if(!text) return;
if(text == 'c') {
suggest([{
content: 'extension' + text,
description: 'chrome://extension'
},
{
content: 'bookmarks' + text,
description: 'chrome://bookmarks'
},
{
content: 'history' + text,
description: 'chrome://history'
}]);
}
});
chrome.omnibox.onInputEntered.addListener((text) => {
console.log('inputEntered: ' + text);
if(!text) return;
var href = '';
if(text.endsWith('extension')) href = 'chrome://extension'
else if(text.endsWith('history')) href = 'chrome://history'
else href = 'chrome://bookmarks'
openUrlCurrentTab(href);
});
function getCurrentTabId(callback){
chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
if(callback) callback(tabs.length? tabs[0].id: null);
});
}
function openUrlCurrentTab(url){
getCurrentTabId(tabId => {
chrome.tabs.update(tabId, {url: url});
})
}
7.桌面通知
使用chrome.notifications API,首先在permissions里声明notifications权限,再在background里创建通知。例如:
chrome.notifications.create('', {
type: 'basic',
iconUrl: 'icons/icon.png',
title: '这是标题',
message: '您刚才点击了自定义右键菜单!'
});
六、框架
1.WXT 框架介绍
WXT 是一个免费的开源浏览器插件开发框架,致力于为开发者带来最好的开发体验和最快的开发速度。
特性:支持所有浏览器:包括 Chrome、Firefox、Edge、Safari 和一切基于 Chromium 的浏览器,大大提高了开发效率和代码的复用性。
一套代码支持 Manifest V2 和 V3 的插件:开发者可以根据需要选择适合的扩展版本,以满足不同浏览器的兼容性和性能要求。
支持 HMR:更新内容不再需要重新加载整个插件,极大地提高了开发效率。
入口点:manifest.json 是根据入口点的文件生成,方便快捷。
默认使用 typescript:使代码更加健壮、易于维护和扩展。
自动导入:与 Nuxt 一样的自动导入功能,默认的接口无需导入即可使用,加速开发过程。
自动下载远程代码:Google Manifest V3 要求拓展程序不依赖远程代码,WXT 满足这一要求。
轻松使用任何带有 vite 插件的前端框架:开发者可以根据项目需求选择合适的前端框架,而不必受限于特定的技术栈。内置包分析工具:方便优化,最小化扩展应用。官方提供多个快速入门模板:方便生成开发者习惯的技术方案。未来还会推出自动压缩、上传、发布功能。
安装与目录结构:执行命令npx wxt@latest init或使用pnpm的pnpx wxt@latest init进行安装。安装后会出现选择起始模板的选项,可根据喜欢的框架选择。目录结构包括.output/构建结果目录、.vscode/和.wxt/配置目录、assets/资源目录、public/资源目录、components/通用组件目录、entrypoints/核心业务源码目录、package.json和wxt.config.ts重要配置文件目录。
配置:打开wxt.config.ts文件,里面有vite的配置,代表不论使用什么框架都构建于vite。WXT 提供defineConfig方法,携带完全的ts类型说明,方便配置。重要配置项包括目录配置(不建议修改官方提供的目录结构)、添加前端框架支持(如在wxt.config.ts文件中安装框架的Vite插件并添加到配置中,可支持Vue、React、Svelte等框架)。
支持 Storage API:WXT 提供简化的 API 来替换browser.storage.* API,可以使用从wxt/storage自动导入的storage或手动导入。所有存储键都必须以其存储区域为前缀,还可以使用local:、session:、sync:或Managed:。如果使用TypeScript,可以向大多数方法添加类型参数来指定键值的预期类型。
支持远程代码:WXT 将自动下载并打包带有url:前缀的导入,满足 Google 对 MV3 的要求,扩展不依赖于远程代码。
2.框架横向对比
WXT 与另一款常用框架 Plasmo 相比,各有优劣。
Plasmo 的优势:已有 7.7k star,在知名度上遥遥领先于 WXT。支持多种前端框架,如 React、Svelte 和 Vue。采用组件化开发方式,提高代码的可维护性和可重用性。内置热更新功能,仅支持 React,但能让开发者在开发过程中实时查看代码更改的效果。提供从开发到测试再到发布的完整解决方案,包括高效开发工具、真实环境测试和自动化发布流程。
WXT 的优势:支持所有前端框架,不受限于特定技术栈。支持自动打开浏览器并安装扩展,提升开发体验。除了支持 React 的热更新外,在内容 / 后台脚本变更时不会重新加载整个插件。未来会推出自动压缩、上传、发布功能,目前已具备内置包分析工具等特性。综上所述,开发者可以根据自己的需求和技术栈选择适合的框架进行 Chrome Extension 开发。
七、总结
Chrome Extension 的开发虽然在技术上存在一定的复杂性,但通过对各种组成部分的理解和运用,开发者能够创造出功能强大、个性化的浏览器扩展。
从基本组成来看,manifest.json 文件作为核心配置,明确了扩展的各项属性和权限;background script 提供了后台运行的能力,可实现各种高级功能;content script 能够与网页交互,实现对页面内容的操作;popup 则为用户提供了直观的交互界面。
在开发过程中,仅需简单的工具即可上手,Chrome 浏览器和带语法高亮的文本编辑器为开发者提供了便捷的开发环境。通过一系列的开发步骤,从创建 manifest 到加载插件、添加功能,开发者可以逐步实现自己的创意。
同时,开发过程中也需要注意一些事项,如 chrome 传递消息 API 的版本变化和本地存储的使用限制等。通过兼容处理和合理配置,可以确保插件在不同版本的 Chrome 浏览器上稳定运行。
Chrome Extension官网有大量的案例可供参考,从简单的速查工具到复杂的开发者工具自定义面板,都体现了其强大的功能。而框架的出现,如 WXT 和 Plasmo,为开发者提供了更高效的开发方式和更多的选择。WXT 以其全面的特性和对多种前端框架的支持,为开发者带来了良好的开发体验和未来的发展潜力。
总之,Chrome Extension 的开发为用户和开发者带来了更多的可能性和便利。无论是提高工作效率、改善浏览体验还是实现个性化需求,Chrome Extension 都发挥着重要的作用。随着技术的不断发展,相信 Chrome Extension 将在未来继续为我们带来更多的惊喜和创新。
DEMO案例:
Chrome extensions: https://developer.chrome.com/docs/extensions/samples?hl=zh-cn
Wxt: https://wxt.dev/examples.html
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)