用 AI 开发浏览器插件:一个能保存便笺的 MV3 扩展
最后更新:
下载四个文件组成的教学样例,观察真正的扩展存储如何工作。已有实际 unpacked 加载和最小流程检查记录。
先看能运行的结果,再决定要增加什么
这个中文便笺教学样例只有输入框、保存按钮和便笺列表。用户手工粘贴一段文字,扩展写入本机存储,再次读取时显示列表。它适合练习 AI 辅助开发中的一条完整小流程:生成文件、检查权限、加载扩展、执行操作、读取真实状态。产品运行时不需要调用模型。
代码来自 2026-09-11 保存的 GPT-5.5 生成结果,证据复核日期为 2026-09-12。实际测试加载了 unpacked 扩展,并在 chrome-extension 地址下打开它自己的 popup 页面;下图就是该扩展页面的真实截图,不是网页仿制图。可以下载示例 ZIP后核对四个源文件。截图中两条文字是自有教学内容,没有真实客户资料。

四个文件里,Manifest 先决定权限和入口
manifest.json 声明扩展版本、名称、权限、popup 页面与后台文件。popup.html 放输入与列表,popup.js 处理读写,worker.js 只有一个空的安装监听器,当前保存功能并不靠它执行。不要把有后台文件理解为已经有持续运行的后台同步。
下面是实际样例的 Manifest。permissions 只有 storage,没有 host_permissions,也没有注入网页的 content_scripts。它处理用户主动粘贴的文字,不读取当前网页。Chrome 官方入门文档解释了 Manifest 和 popup 入口关系,参见 Hello World 扩展教程,核对日期 2026-09-12;教程说明不代替本页样例的实际测试。
{
"manifest_version": 3,
"name": "中文便笺教学样例",
"version": "1.0.0",
"permissions": ["storage"],
"action": {"default_popup": "popup.html"},
"background": {"service_worker": "worker.js"}
}保存成功要看存储结果,不只看页面多了一行
popup.js 初次打开时读取 notes,保存时先 trim 输入,再读取已有数组,追加非空文字,写回 chrome.storage.local,最后重新渲染。实际渲染用 textContent 放入列表项,输入的文字不会被当成 HTML 执行。下方摘录原样例的保存监听器,note、save、render 由同一文件其他部分定义。
Chrome Storage API说明存储读写是异步操作,local 区域用于本机持久化,卸载扩展会清理其中数据,核对日期 2026-09-12。当前代码在写入前就清空输入,也没有完整处理存储失败;正常流程通过不等于异常情况下不会丢草稿。这是继续开发时应优先解决的问题。
save.addEventListener("click", () => {
const text = note.value.trim();
note.value = "";
chrome.storage.local.get({notes: []}, data => {
const notes = Array.isArray(data.notes) ? data.notes : [];
if (text) notes.push(text);
chrome.storage.local.set({notes}, () => render(notes));
});
});按相同顺序加载并复核最小流程
将示例解压到独立目录,确认 manifest.json 就在所选目录根部。打开 Chrome 扩展管理页,启用开发者模式,选择“加载已解压的扩展程序”,选中该目录;然后打开扩展的 popup。具体本地加载入口见 Chrome 官方加载说明,核对日期 2026-09-12。浏览器设置可能影响开发模式,遇到限制应按本机管理要求处理。
在干净的测试配置中保存第一条文字,刷新扩展页面确认它仍在,再保存第二条。随后保持输入为空点击保存,确认列表仍为两条,并在开发者工具里检查存储与页面错误。原取证做的是第一条保存后刷新,再新增第二条;不要把它扩大成已测浏览器重启、跨设备同步或任意多窗口并发。复测若使用已有数据,先导出需要的便笺,不能为了凑两条结果清掉用户原始内容。
把实际通过项与尚未覆盖项摆在一起
原始记录确认 Manifest V3 与唯一权限 storage,真实加载扩展,最终存储两条便笺,空输入没有增加条数,捕获的页面运行错误数组为空。实现没有模型请求和网络业务逻辑。页面截图只能说明当时显示的结果,持久化结论来自存储读取与刷新后的检查,而不是从截图推测。
这份证据刻意保持范围很小。它没有覆盖存储容量耗尽、快速连点、两个扩展页面同时保存、浏览器升级和商店安装。当前数组读改写遇到并发可能覆盖其他写入;两条顺序写入通过不能证明不存在这种问题。下面是已经完成和下一阶段的清晰分界。
| 检查项 | 记录结果 | 解释 |
|---|---|---|
| unpackedExtensionLoaded | true | 实际扩展环境已加载 |
| permissions | [storage] | 没有请求网页主机权限 |
| saved | 2 | 最终本地存储包含两条便笺 |
| reloadPersists | true | 第一条在页面刷新后仍可读取 |
| emptyIgnored / runtimeErrors | true / [] | 空输入不新增,所测页面无运行错误 |
| 并发写入、导出恢复、商店分发 | 未验证 | 不能由上面的最小流程推导通过 |
下一轮先补丢稿与恢复,再考虑摘要功能
让 AI 先把清空输入移到确认写入成功之后,写入失败时保留原文并给出可恢复状态。对同一 popup 加提交中的互斥状态,减少连点重复;多窗口仍需统一写入口或适当事务方案,并用并发测试验证。便笺还应有稳定 id 和创建时间,删除与导出按 id 操作,避免文本相同就删错项。
导出可以使用有 schemaVersion 的 JSON,再给导入做类型、条数和大小限制;合并与覆盖要让用户明确选择。备份文件中有用户内容,不应自动上传。存储损坏时先保留原数据供恢复,不要静默转换成空数组后覆盖。下面是教学改造任务,不代表 ZIP 已包含这些增强功能。
基于原始 MV3 便笺样例继续开发,保持 storage 唯一权限。
先复现:顺序保存两条、刷新保留、空输入不新增。
写入成功后才清空草稿;读取或写入失败时保留输入。
给便笺增加 id、createdAt 和导出 schemaVersion,说明旧数组如何迁移。
导入先校验文件,再预览合并结果;覆盖操作需用户确认。
补测快速连点、两个页面写入、失败后重试、导出后恢复。
交付真实结果与未覆盖项,不以静态 HTML 代替扩展加载。AI 写扩展,与扩展调用 AI 是两件事
当前样例的 AI 参与发生在开发阶段:模型生成文件,由本地环境加载和验证。以后增加“摘要这条便笺”,才涉及把用户选择的内容送入模型。届时需要解释发送什么、何时发送、结果存在哪里,并让用户能够取消;本地保存功能不能因为摘要失败就不可用。
服务密钥不能打包进扩展源码。面向多人使用时,由受控服务端处理身份、权限、请求限制与费用;个人自备 Key 的模式也要评估明文存储和设备访问风险,不能把 chrome.storage 当作密码保险箱。开发工具接入从 Cline 配置开始,具体请求能力核对接口文档和模型目录,不要仅凭工具存在自定义地址就承诺兼容。
交付 ZIP 之后,还需要怎样的维护承诺
交付包应对应固定版本,附源文件清单、权限说明、加载办法、数据保存位置和已知问题。升级前验证旧数据迁移,卸载前提醒用户先导出;客户付费购买的是明确约定的可用功能与支持范围,而不是一张扩展截图。浏览器种类、版本与安装方式都应写进验收记录,不能把一次 Chromium 测试写成所有浏览器兼容。
本页没有商店发布记录,没有收费用户和收益数字。便笺保存本身不产生模型调用,开发支出与将来摘要调用支出分别记账,当前模型价格查看价格页。评估开发工具投入可以复用这个固定任务,进入订阅与 API 比较;若任务主要处理本地目录,则转向桌面文件工具。
常见问题
示例是真正的浏览器扩展,还是普通网页?
是真实 unpacked 扩展。测试在扩展自身的 chrome-extension 页面操作并读取 chrome.storage;截图不是仅用普通网页仿出的界面。
为什么只需要 storage 权限?
当前功能只保存用户手工输入的文字,不读取网页、标签页或浏览记录。新需求需要新权限时,应单独解释必要性并重新检查。
两条便笺是否证明任何情况下都不会丢数据?
不证明。现有检查覆盖顺序写入、一次页面刷新和空输入;多窗口竞争、存储错误和升级恢复仍需测试,原代码也需要补齐错误处理。
能直接装到所有浏览器或发布到商店吗?
本页只有所记录 Chromium 扩展环境的最小流程证据。其他浏览器与分发方式应分别验证,当前商店要求需到官方平台复核。
保存便笺需要购买 API 吗?
这个样例不需要。AI 用于辅助开发,运行时仅使用本机扩展存储;以后增加模型摘要才需要另外设计请求和费用控制。