Chrome 插件开发指南:从 Web 到扩展,以及「网页内容总结助手」实战

Chrome 插件开发指南:从 Web 到扩展,以及「网页内容总结助手」实战
本文结合开源项目 网页内容总结助手(React + Vite + Manifest V3)总结插件开发中的注意点,并对比插件开发与普通 Web 开发的差异,方便从前端转型或入门扩展开发的同学少踩坑。

一、先安利一下:网页内容总结助手

网页内容总结助手 是一款基于 React + Vite 构建的 Chrome 扩展,主打「一键总结网页并导出 Markdown」:

  • 一键提取正文并调用 ModelScope + DeepSeek 做 AI 总结,或使用本地 mock
  • 选择页面任意区域进行总结(高亮选择模式)
  • 多种输出类型:总结、博客、文章、报告、要点列表
  • 设置本地持久化:API Key、总结字数等存于 chrome.storage.sync,无需后端
  • 遵循 Manifest V3,适合作为学习或二次开发模板

如果你在做阅读摘要、知识整理或内容再生产,欢迎在 Chrome 应用商店或通过「加载已解压的扩展程序」安装使用,也欢迎 Star / Fork 项目参与改进。

下面进入正题:插件开发要注意什么,和普通 Web 开发有什么不同。


二、插件开发 vs Web 开发:核心差异

维度普通 Web 开发Chrome 扩展开发
运行环境单一页面或 SPA,同源策略限制多个隔离环境:Popup、Background(如 Service Worker)、Content Script、可选 Offscreen
脚本加载方式可自由使用 <script type="module">Popup 可用 ESM;Content Script 按普通脚本注入,不能直接写顶层 import
存储常用 localStorage、Cookie、后端 DB推荐 chrome.storage.sync / chrome.storage.local,跨页面且可同步(sync)
网络与权限受 CORS 限制,需后端或代理在 manifest 中声明 host_permissions 后可直连指定域名,无 CORS 问题
与页面交互直接操作当前页 DOM/JSContent Script 与页面共享 DOM,与 Popup/Background 通过 消息 通信,不能直接共享变量
构建与部署通常单入口打包,部署到服务器多入口:Popup 页面 + Content Script(+ Background);加载的是本地目录(如 dist),不是 URL
安全与审核主要防 XSS、CSRF、敏感信息泄露还需注意权限最小化、Manifest V3 规则、商店审核策略

这些差异会直接影响到你的技术选型、构建配置和调试方式,下面按「开发时需要注意的情况」展开。


三、开发插件时需要注意的情况(结合本项目)

1. Manifest:权限与入口要写对

扩展的「合同」是 manifest.json(本项目在 public/manifest.json,构建时拷贝到 dist)。

  • permissions:只申请必要权限,例如本插件用到了 activeTabscriptingdownloadsstorage
  • host_permissions:调用外部 API 时必须声明域名,例如 ModelScope:"https://api-inference.modelscope.cn/*",否则请求会被拦截。
  • content_scripts.js:写的是构建后的文件名(如 content.js),且该文件必须是单文件、无顶层 ESM(见下一条)。

权限过多会触发商店或用户的不信任;少了则功能无法使用,建议每加一个能力就对照 Manifest 文档 补全。

2. Content Script 不能直接用 ES Module

这是从 Web 开发转扩展时最容易踩的坑之一。

  • 原因:Content Script 由 Chrome 按「传统脚本」注入到页面,不支持type="module",遇到顶层 import 会报错:Cannot use import statement outside a module
  • 本项目做法:保留 Vite 打 Popup(ESM),单独用一份 Vite 配置vite.content.config.js)把 src/content.js 打成 IIFE 单文件,依赖(如 marked)打包进去,产出 dist/content.js。构建命令形如:vite build && vite build --config vite.content.config.js

若你用的是其它打包器,思路一致:Content 入口单独打包,输出格式为 IIFE(或其它非 ESM),且不拆成多个 chunk(避免注入多个 script)。

3. Popup 与 Content Script:两个世界,靠消息通信

  • Popup:点击图标打开的页面,和普通网页一样跑在扩展自己的环境中,可以随意用 React、Vue、ESM。
  • Content Script:注入到用户正在浏览的网页里,能访问 DOM,但和 Popup/Background 不共享 JS 变量

二者只能通过 chrome.runtime.sendMessage / chrome.tabs.sendMessage 通信。例如本插件中:

  • Popup 发 startSelection → Content 进入高亮选择模式;
  • Content 把选中的文本通过消息回传 → Popup 再调 AI 或 mock 总结。

另外,若 Popup 打开时当前页尚未注入 Content Script,sendMessage 会报「Receiving end does not exist」。本项目在 Popup 里对这类调用做了 try/catch.catch(),必要时先通过 chrome.scripting.executeScript 注入再发消息,避免未捕获异常。

4. 没有「后端」时的配置持久化:chrome.storage

插件可以是纯前端,没有自己的服务器。用户设置(如 API Key、总结字数)需要持久化时,用 chrome.storage 即可。

  • chrome.storage.sync:跨设备同步(需用户登录 Chrome),适合设置、偏好。
  • chrome.storage.local:仅本机,适合较大或不同步的数据。

本项目把 API Key、总结字数、内容类型等统一存到 chrome.storage.sync。Popup 打开时从 storage 读入并写入 React state;用户在设置页修改后写回 storage,下次打开或其它设备上都会生效。注意:不要在前端代码里写死 API Key,一律从 storage 或用户输入来,并在 UI 上对「未配置 / 密钥错误」做明确提示(如本插件的设置校验与错误文案)。

5. 加载的是「目录」而不是「网址」

和普通 Web 不同,扩展在本地是以目录形式加载的(开发者模式下的「加载已解压的扩展程序」)。因此:

  • 构建产物必须包含完整扩展:至少要有 manifest.json、Popup 的 HTML/JS、Content Script 的 JS 等,且路径要和 manifest 里写的一致。
  • 本项目使用 Vite,Popup 和 Content 分别构建,最终都输出到 dist,并依赖 public 下的 manifest.json 被拷贝到 dist。加载时选择 dist 目录即可。

开发时若改了代码,需要重新 pnpm run build(或 npm run build),并在 chrome://extensions 里点击扩展的「重新加载」。

6. 调试方式与普通 Web 的差异

  • Popup:右键扩展图标 →「检查弹出内容」,会打开该 Popup 的 DevTools,和普通页面一样打断点、看 Network。
  • Content Script:在被注入的网页上按 F12,在 Sources 里找到扩展的 content.js,或在 Console 里看到来自 content script 的 log。
  • Background(若使用):在 chrome://extensions 里点击该扩展的「Service Worker」链接打开 DevTools。

Popup 用 npm run dev 可以单独在浏览器里跑 React 界面,但和真实扩展环境(storage、消息、content)仍有差别,完整流程建议以「构建 → 加载 dist」为准做验证。

7. 安全与体验上的小建议

  • 权限:只声明真正用到的权限和 host;API Key 等敏感信息只存 storage,不写进源码、不提交仓库。
  • 错误与降级:如本插件在「未配置 Key / 密钥错误」时提示并打开设置页;其它 API 失败时可选降级到本地 mock,避免白屏或静默失败。
  • 用户提示:总结前可对字数、内容类型做校验;保存设置后给「设置已保存」等反馈,提升可感知的稳定性。

四、小结:从 Web 到插件的心智转换

  • 多环境:Popup / Content / Background 各是一块运行环境,用消息和 storage 串联,而不是一个单页应用里的组件通信。
  • 构建多入口:至少区分「Popup(可 ESM)」和「Content(要 IIFE)」两套构建,产物放到同一目录供 manifest 引用。
  • 权限与存储:manifest 里声明权限和 host;无后端时用 chrome.storage 做配置持久化,并从设计上避免硬编码密钥。
  • 调试与发布:以「构建 → 加载 dist → 在真实扩展环境里点一点」为主;发布到商店前再对照审核策略做一遍检查。

如果你正在做或想做一个「和网页内容强相关」的小工具(总结、翻译、高亮、剪藏等),欢迎参考或直接基于 网页内容总结助手 的架构来改:React + Vite、Manifest V3、Content 与 Popup 分离构建、storage 持久化,这些模式都可以复用。也欢迎提 Issue 和 PR,一起把插件做得更好用。


项目仓库
https://gitee.com/qiaoyuning/ai-page-summarizer.git

本地安装pnpm install && pnpm run build,在 Chrome 中加载 dist 目录即可使用。

Read more

Flutter 组件 powersync_attachments_helper 的适配 鸿蒙Harmony 实战 - 驾驭分布式附件同步、实现鸿蒙端大文件离线存储与生命周期自动化管理方案

Flutter 组件 powersync_attachments_helper 的适配 鸿蒙Harmony 实战 - 驾驭分布式附件同步、实现鸿蒙端大文件离线存储与生命周期自动化管理方案

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 powersync_attachments_helper 的适配 鸿蒙Harmony 实战 - 驾驭分布式附件同步、实现鸿蒙端大文件离线存储与生命周期自动化管理方案 前言 在鸿蒙(OpenHarmony)生态的分布式多媒体协作、工业设备故障图片上报以及需要频繁处理大量音频/视频附件的专业级应用开发中,“非结构化数据与 SQL 逻辑的一致性同步”是决定应用能否在大规模复杂场景下存活的技术深水区。面对一条已经同步成功的“设备巡检记录”。如果其关联的“高清故障原图”因为同步时机错位、由于存储空间不足导致的本地缓存被回收,或者是在鸿蒙手机与平板之间由于同步策略不同步导致的文件路径失效。那么不仅会导致用户在查看详情时看到令人沮丧的“附件丢失”占位图,更会严重削弱政务类资产审计的底层严密性。 我们需要一种“逻辑关联、物理对齐”的附件治理艺术。 powersync_attachments_helper 是一套专为 PowerSync 设计的附件同步

By Ne0inhk
微服务链路追踪实战:SkyWalking vs Zipkin 架构深度解析与性能优化指南

微服务链路追踪实战:SkyWalking vs Zipkin 架构深度解析与性能优化指南

目录 1. 链路追踪:分布式系统的“X光机” 1.1 从单体到微服务:排查困境的演变 1.2 链路追踪的核心价值矩阵 2. 核心原理解析:Trace、Span与上下文传播 2.1 基本概念:一次请求的完整“病历” 2.2 上下文传播:Trace ID的“接力赛” 2.3 采样算法:平衡精度与开销的智慧 3. SkyWalking深度解析:无侵入监控的艺术 3.1 架构全景:从Agent到UI的完整链路 3.2 字节码增强:Java Agent的魔法 3.3 生产环境配置模板 3.4 性能特性与调优 4.

By Ne0inhk
卷积神经网络(CNN)进阶:经典架构解析与实战开发

卷积神经网络(CNN)进阶:经典架构解析与实战开发

卷积神经网络(CNN)进阶:经典架构解析与实战开发 💡 学习目标:掌握CNN的经典进阶架构设计思路,理解不同架构的核心创新点,能够基于经典架构开发定制化图像任务模型。 💡 学习重点:LeNet-5、AlexNet、VGGNet、ResNet的核心结构与改进逻辑,基于PyTorch实现ResNet-50并完成图像分类任务。 49.1 卷积神经网络进阶的核心驱动力 卷积神经网络从最初的简单结构发展到深度模型,核心驱动力是解决深层网络的性能瓶颈和提升特征提取的效率与精度。 在早期CNN的应用中,研究人员发现两个关键问题: 1. 网络深度增加到一定程度后,会出现梯度消失或梯度爆炸问题,导致模型无法收敛。 2. 简单堆叠卷积层的方式,会造成特征冗余和计算资源浪费,模型泛化能力受限。 ⚠️ 注意:CNN的进阶过程不是单纯的“堆层数”,而是通过结构创新、参数优化和训练技巧的结合,实现性能的突破。 ✅ 结论:经典CNN架构的每一次升级,都针对当时的技术痛点提出了创新性解决方案,掌握这些方案的设计思路,比记住网络结构更重要。 49.2 经典CNN架构深度解析 49.2.1

By Ne0inhk