Chrome 浏览器插件(Extension)是前端开发者绕不开的一项重要技能。随着 Manifest V3 标准的全面推行,插件开发的范式也发生了巨大变化。本文将以 Service Worker 为核心,详述一个完整 Chrome 插件的开发全流程。
一、Manifest V3 与 V2 的关键区别
Chrome 在 2024 年正式停止了对 Manifest V2 的支持,V3 架构带来了以下关键变化:
- Background Page 变为 Service Worker:不再长期驻留内存,空闲时会被回收,需要事件唤醒
- 网络请求改用 declarativeNetRequest:不再支持 webRequest API 的阻塞模式
- Remotely Hosted Code 被禁止:所有 JavaScript 必须打包在插件内
- Promises 全面支持:大部分 API 返回 Promise,告别回调地狱
二、创建 manifest.json
manifest.json 是插件的核心配置文件,声明了插件的身份、权限和入口点:
{
"manifest_version": 3,
"name": "我的第一个插件",
"version": "1.0.0",
"description": "一个学习用的 Chrome 插件示例",
"permissions": ["storage", "activeTab", "scripting"],
"host_permissions": ["https://api.example.com/*"],
"background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "icon16.png",
"48": "icon48.png",
"128": "icon128.png"
}
},
"content_scripts": [{
"matches": ["https://*.example.com/*"],
"js": ["content.js"],
"css": ["styles.css"]
}]
}
注意:host_permissions 必须显式声明跨域请求的目标域名,否则 Manifest V3 下所有跨域请求都会被拦截。permissions 中的 storage 用于访问 chrome.storage API。
三、Service Worker 的生命周期管理
V3 的 Service Worker 不再像 V2 那样持续运行,而是在被需要时激活,空闲约 30 秒后自动终止。这意味着全局变量无法可靠保存状态,必须使用 chrome.storage 持久化:
// background.js - Service Worker
chrome.runtime.onInstalled.addListener(() => {
chrome.storage.local.set({ installTime: Date.now() });
console.log('插件已安装');
});
// 监听消息
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg.type === 'get_data') {
chrome.storage.local.get(['token'], ({ token }) => {
fetch('https://api.example.com/data', {
headers: { 'Authorization': `Bearer ${token}` }
})
.then(res => res.json())
.then(data => sendResponse({ ok: true, data }))
.catch(err => sendResponse({ ok: false, error: err.message }));
});
return true; // 必须返回 true 表示异步响应
}
});
四、Content Script 与页面通信
Content Script 运行在目标网页的上下文中,可以访问 DOM 但不能直接使用 chrome.* API 的大部分功能。与 Service Worker 的通信通过消息传递完成:
// content.js
// 从页面中提取数据
const text = document.querySelector('h1')?.innerText;
// 发送给 Service Worker
chrome.runtime.sendMessage(
{ type: 'page_data', text, url: location.href },
(response) => {
console.log('Service Worker 回复:', response);
}
);
// 监听来自 Service Worker 的消息
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg.type === 'highlight') {
document.body.style.backgroundColor = '#fef9e7';
sendResponse({ ok: true });
}
});
五、Popup 弹窗开发
Popup 是用户点击工具栏图标时弹出的小窗口,本质是一个独立的 HTML 页面:
<!-- popup.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body{width:320px;padding:16px;font-family:sans-serif}
h2{font-size:16px;color:#333;margin-bottom:12px}
button{width:100%;padding:10px;background:#1976d2;color:#fff;
border:none;border-radius:6px;cursor:pointer}
button:hover{background:#1565c0}
.status{margin-top:10px;font-size:13px;color:#666}
</style>
</head>
<body>
<h2>数据分析助手</h2>
<button id="analyze">分析当前页面</button>
<div class="status" id="status"></div>
<script src="popup.js"></script>
</body>
</html>
// popup.js
document.getElementById('analyze').addEventListener('click', async () => {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
const response = await chrome.tabs.sendMessage(tab.id, { type: 'analyze' });
document.getElementById('status').textContent = '分析完成:' + JSON.stringify(response);
});
六、Options 设置页面
Options 页面可以为用户提供配置入口,如 API 地址、偏好设置等。在 manifest.json 中声明后,右键插件图标即可看到"选项"入口:
// manifest.json 中添加
"options_ui": {
"page": "options.html",
"open_in_tab": true
}
七、打包与发布
开发完成后,需要将插件打包为 .crx 或 .zip 文件:
- 本地测试:打开 chrome://extensions/ → 开启"开发者模式" → 加载已解压的扩展程序
- 生产打包:使用 npm run build(如 Webpack)压缩代码后,将产物放入 dist 目录
- Chrome Web Store:需注册开发者账号(一次性费用 5 美元),上传 .zip 包并填写描述后提交审核
总结
Chrome 插件开发虽然入门门槛不高,但要写出一个高质量、稳定运行的插件,需要对 Manifest V3 规范有深入理解。本文涵盖了从配置文件到消息通信的全流程,希望能为有志于插件开发的读者提供一个系统的参考框架。在实际项目中,建议多加测试尤其是 Service Worker 的唤醒逻辑,这是 V3 架构中最容易出现隐蔽 Bug 的地方。