Chrome浏览器插件经常以CRX文件出现,但真正开发一个插件时,并不是直接编辑CRX。开发者通常先建立一个普通文件夹,在里面放入manifest.json、JavaScript、HTML、CSS和图标等文件,完成调试后再打包或提交到Chrome应用商店。
因此,要理解Chrome插件制作,可以先把它分成两层:一层是插件本身的源码目录结构,另一层才是用于签名和分发的CRX安装包。

CRX是什么
CRX是Chrome Extension的打包文件格式之一。已经打包的Chrome扩展通常表现为一个.crx文件,而开发阶段常见的则是一个“未打包扩展程序”目录。
两者可以简单理解为:
开发阶段: my-extension/ ├── manifest.json ├── popup.html ├── popup.js ├── service-worker.js └── icons/ ↓ 打包、签名 my-extension.crx
CRX并不是单纯把文件夹后缀改成.crx。当前CRX3格式在文件前部包含版本、签名和公钥证明等头部数据,后面才是扩展文件的ZIP归档内容。
从Chromium公开的CRX3格式定义来看,其结构大致可以理解为:
CRX3文件 ├── Magic Number:Cr24 ├── CRX格式版本:3 ├── Header长度 ├── CrxFileHeader │ ├── 签名信息 │ └── 公钥证明等数据 └── ZIP归档 ├── manifest.json ├── JavaScript ├── HTML ├── CSS └── 图片等资源
所以,CRX更准确地说是“带有签名信息的Chrome扩展安装包”。
插件目录长什么样
一个实际Chrome扩展的目录可以很简单,也可以包含很多模块。例如:
my-extension/ ├── manifest.json ├── service-worker.js ├── content.js ├── popup/ │ ├── popup.html │ ├── popup.css │ └── popup.js ├── options/ │ ├── options.html │ └── options.js └── icons/ ├── icon16.png ├── icon48.png └── icon128.png
并不是每个插件都需要这些文件。真正必不可少的是根目录中的manifest.json,其他文件是否存在取决于插件功能。
manifest.json是核心
manifest.json相当于Chrome插件的配置清单。浏览器通过它判断插件叫什么、版本是多少、需要哪些权限、运行哪些脚本,以及点击工具栏图标后应该打开什么界面。
当前Chrome扩展平台使用Manifest V3,新开发插件通常应该使用:
{
"manifest_version": 3,
"name": "我的Chrome插件",
"version": "1.0.0",
"description": "一个简单的Chrome扩展示例"
}其中最基础的字段包括:
manifest_version:扩展清单规范版本;name:插件名称;version:插件版本号;description:插件功能说明。
随着功能增加,还会使用permissions、host_permissions、background、content_scripts和action等配置。
几个常见组成部分
Popup弹窗
点击浏览器工具栏中的插件图标后出现的小窗口,一般由HTML、CSS和JavaScript组成。
"action": {
"default_popup": "popup/popup.html"
}密码生成器、二维码工具、网页辅助工具等插件,经常把主要操作界面放在Popup中。
Content Script
Content Script用于在指定网页中运行代码,可以读取或修改当前页面DOM。
例如:
"content_scripts": [
{
"matches": ["https://example.com/*"],
"js": ["content.js"]
}
]网页翻译、元素修改、广告隐藏、页面增强等功能,通常都会涉及Content Script。
它虽然运行在网页环境附近,但默认处于扩展的隔离执行环境,与网页自己的JavaScript并不是完全相同的上下文。
Service Worker
Manifest V3使用扩展Service Worker承担后台事件处理工作。
"background": {
"service_worker": "service-worker.js"
}它可以监听插件安装、标签页变化、消息通信和浏览器API事件。
与早期Manifest V2长期运行的Background Page不同,Service Worker会在需要时启动,空闲后可能被停止,因此不能依赖全局变量长期保存状态。
Options页面
配置比较多的插件可以提供独立设置页,例如保存API Key、网站规则、主题和功能开关。
"options_page": "options/options.html"
权限怎么理解
Chrome插件并不是默认可以读取所有网页和浏览器数据。需要使用敏感能力时,应在manifest.json中声明相应权限。
例如:
{
"permissions": [
"storage",
"activeTab",
"scripting"
],
"host_permissions": [
"https://example.com/*"
]
}permissions主要声明浏览器API能力,host_permissions则用于声明插件需要访问哪些网站。
常见权限包括:
storage:保存插件配置;activeTab:临时访问当前活动标签页;scripting:向网页执行脚本;tabs:使用部分标签页相关能力;contextMenus:添加右键菜单。
权限不是越多越方便。权限范围过大不仅会增加安全风险,也可能在安装时向用户显示更敏感的权限提示。开发插件时通常应该按照实际功能申请最小权限。
做一个最简单的插件
下面可以制作一个简单示例:点击插件按钮后,把当前网页背景改成浅黄色。
建立目录:
page-color/ ├── manifest.json ├── popup.html └── popup.js
manifest.json:
{
"manifest_version": 3,
"name": "页面背景修改器",
"version": "1.0.0",
"description": "点击按钮修改当前网页背景",
"permissions": [
"activeTab",
"scripting"
],
"action": {
"default_popup": "popup.html"
}
}popup.html:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>页面工具</title> </head> <body> <button id="changeColor">修改页面背景</button> <script src="popup.js"></script> </body> </html>
popup.js:
document.getElementById("changeColor").addEventListener("click", async () => {
const [tab] = await chrome.tabs.query({
active: true,
currentWindow: true
});
await chrome.scripting.executeScript({
target: {
tabId: tab.id
},
func: () => {
document.body.style.backgroundColor = "#fff7d6";
}
});
});这已经构成一个最基础的Manifest V3插件。
怎么加载测试
开发阶段不需要先制作CRX。
在Chrome地址栏打开:
chrome://extensions/
然后:
打开右上角“开发者模式”;
点击“加载已解压的扩展程序”;
选择刚才创建的
page-color目录;插件会出现在扩展程序列表中;
打开普通网页测试功能。
修改代码后,可以在扩展管理页面点击重新加载按钮。
修改manifest.json、Service Worker或Content Script后通常需要重新加载插件;修改Content Script后,还需要刷新对应网页才能看到新代码效果。
如何制作CRX
本地测试完成后,可以通过Chrome自身的打包功能生成CRX。
进入:
chrome://extensions/
开启开发者模式,点击“打包扩展程序”,选择扩展程序根目录。
第一次打包通常会生成:
page-color.crx page-color.pem
.crx是打包后的扩展文件。
.pem是私钥文件,用于后续以相同身份重新签名扩展,应该妥善保存,不能上传到公开GitHub仓库或随插件一起公开分发。
也可以通过Chrome命令行进行打包:
chrome.exe --pack-extension=C:\extension\page-color
已有私钥时可以指定:
chrome.exe --pack-extension=C:\extension\page-color ^ --pack-extension-key=C:\keys\page-color.pem
开发目录、ZIP和CRX的区别
| 形式 | 主要用途 |
|---|---|
| 源码目录 | 开发、调试,通过“加载已解压扩展”运行 |
| ZIP | 常用于提交Chrome应用商店 |
| CRX | 签名后的Chrome扩展分发包 |
| PEM | 本地打包使用的私钥,需要保密 |
这里有一个常见误区:发布Chrome应用商店时,并不是一定要自己先制作CRX。
正常首次提交Chrome Web Store时,开发者通常把扩展目录压缩成ZIP,并保证manifest.json位于ZIP根目录,再上传开发者后台。通过审核和发布流程后,由Chrome Web Store负责正式分发和签名。
CRX能直接拖进Chrome安装吗
现在的Chrome对第三方CRX安装有较严格限制。
开发者自己测试插件时,最直接的方法仍然是打开开发者模式并加载未打包目录。
面向普通Windows和macOS用户公开分发时,Chrome官方支持的主要方式是Chrome Web Store;企业环境还可以通过浏览器管理策略部署扩展。普通用户不能再把任意来源的CRX简单理解成“下载后双击即可安装的软件包”。
因此,自己制作CRX与让普通用户稳定安装CRX是两个不同问题。
Manifest V3带来的变化
现在制作Chrome插件时,需要特别注意Manifest V3。
相比早期Manifest V2,它有几个比较明显的变化:
后台页面改为Service Worker模式;
权限划分更加明确;
扩展代码不能依赖远程托管JavaScript动态执行;
内容安全策略更加严格;
网络请求修改等部分API使用方式发生变化。
例如,在普通网站中常见的下面这种写法:
<script src="https://cdn.example.com/library.js"></script>
不能简单照搬到Manifest V3扩展的普通页面中执行远程代码。需要使用的JavaScript库通常应该随扩展一起打包,并遵守Chrome Web Store的相关政策。
一个完整插件如何协作
稍复杂的Chrome插件通常不是所有代码都写在一个JavaScript文件里,而是多个环境互相通信。
用户点击插件图标 ↓ Popup ↓ 发送消息 ↓ Service Worker ↓ 调用Chrome API ↓ Content Script ↓ 读取或修改网页DOM
例如一个网页SEO检查插件可能这样工作:
Content Script读取页面Title、Description、H标签和链接;
Popup负责显示分析结果;
Service Worker处理标签页、网络请求或其他浏览器事件;
Storage保存用户设置和历史配置。
并不是每个插件都需要完整使用这套结构。一个简单Popup工具甚至可以只有manifest.json、HTML和JavaScript几个文件。
制作时容易踩的坑
第一个问题通常是manifest.json格式错误。它必须是合法JSON,不能像普通JavaScript对象一样随意加入注释。
第二个问题是权限申请过多。例如一个只修改当前网页的插件,没有必要一开始就申请访问所有网站。
第三个问题是把Service Worker当成永远运行的后台程序。Manifest V3会在空闲时停止它,需要长期保存的数据应该放入chrome.storage等持久化位置。
另一个常见问题是把网站开发经验完全照搬到扩展中,例如使用内联JavaScript、eval()或动态加载远程执行代码。这些行为会受到扩展内容安全策略和Chrome Web Store政策限制。
如何判断需要哪些文件
制作插件前,不必先套一个复杂目录模板,可以从功能倒推结构。
只需要点击图标显示一个工具:
manifest.json popup.html popup.js
需要自动修改网页:
manifest.json content.js
需要监听浏览器后台事件:
manifest.json service-worker.js
需要同时操作网页、保存配置并提供界面:
manifest.json service-worker.js content.js popup/ options/ icons/
Chrome扩展真正的核心并不是CRX后缀,而是Manifest定义的权限、运行环境以及各模块之间的协作关系。CRX只是开发完成后的打包形式之一。
对于刚接触Chrome插件开发的人,最合适的顺序通常是先写一个Manifest V3的最小扩展,通过chrome://extensions加载目录完成调试,再逐步加入Content Script、Service Worker和权限,最后根据用途选择打包CRX或提交Chrome Web Store。这样比直接研究一个现成CRX文件更容易理解整个扩展体系。
poxiaoxi博客
精彩评论