首页
/ Web-Dev-For-Beginners 浏览器扩展课程第一部分:理解浏览器与打造第一个 Manifest V3 碳足迹扩展

Web-Dev-For-Beginners 浏览器扩展课程第一部分:理解浏览器与打造第一个 Manifest V3 碳足迹扩展

2026-09-06 13:34:24作者:蔡丛锟

本篇基于 Web-Dev-For-Beginners 课程的浏览器扩展项目第一部分(5-browser-extension/1-about-browsers),系统讲解浏览器的工作机制(URL 解析、HTTP 请求、渲染引擎、缓存与 cookies)、浏览器扩展的安装与加载流程,并给出一个可复制、可运行的实战路径:基于 starter 代码库、Webpack 5 构建链和 Manifest V3 清单,动手写出一个展示本地区域碳足迹的 Edge/Chrome 扩展的第一阶段——配置表单与结果界面的 HTML 搭建与首次构建加载。读完本文,你将能够解释浏览器处理网页请求的完整链路,并独立完成扩展的 npm installnpm run build 与 "Load Unpacked" 开发者模式安装闭环。

扩展在 Edge 浏览器中的安装流程截图,展示 edge://extensions 页面与设置菜单

一、浏览器是什么:从 WorldWideWeb 到现代渲染引擎

浏览器扩展(Browser Extension)是为浏览器添加额外功能的迷你应用。但在动手构建之前,必须先理解浏览器本身的工作方式。

定义:浏览器是让用户能够访问服务器上的内容、并将其呈现为网页的软件应用。✅ 一点历史:第一个浏览器名为 WorldWideWeb,由 Sir Timothy Berners-Lee 于 1990 年创建。

浏览器处理一次网页请求的完整链路(原文档核心内容):

  1. 用户输入 URL(Uniform Resource Locator)地址连接互联网;
  2. 通过 httphttps 协议(Hypertext Transfer Protocol)访问资源;
  3. 浏览器与 Web 服务器通信,拉取网页内容(HTML、CSS、JavaScript);
  4. 此刻,浏览器的**渲染引擎(Rendering Engine)**负责在用户的设备上——无论是手机、台式机还是笔记本——将内容输出为可视化页面。

除了渲染,浏览器还提供两项关键能力:

  • 内容缓存(Caching):将已获取的网页资源缓存下来,避免每次访问都回到服务器取回;
  • Cookies 存储:cookies 是包含浏览活动记录所需信息的小型数据,浏览器负责持久化保存它们。

这两项能力正是后续课程中扩展功能(本地存储 API 键、区域代码)所依赖的浏览器基础设施。

浏览器并不相同:跨浏览器差异是必须面对的约束

原文档强调了一个关键点:所有浏览器并不完全一样。每个浏览器各有优劣,专业 Web 开发者必须理解如何让网页在各种浏览器(cross-browser)下都正常工作,其中就包括小视口(viewport)控制(如手机屏幕)与离线(offline)处理等任务。

  • 规划功能时,用 caniuse 网站(原文推荐加入书签)上的技术支持清单,可以判断你的技术在各主流浏览器的支持程度,从而决定优先支持哪些浏览器;
  • 想知道你的用户群中哪些浏览器最流行?查看**分析(analytics)**数据——Web 开发流程中会安装各类分析包,它们会告诉你不同主流浏览器中的使用占比,帮助你确定支持优先级。

二、为什么做浏览器扩展:小而专,解决重复操作

做扩展的动因很直接:当某个重复性操作需要频繁进出浏览器时,扩展是最便捷的答案。原文档给出的典型场景:

  • 在多个网页中反复查看颜色值 → 安装一个 color-picker 类扩展;
  • 难以记住各站点的密码 → 安装 password-management 类扩展。

浏览器扩展往往把数量有限的几项任务做得非常精到,这也是它易于开发、趣味十足的原因。✅ 自检问题:你最喜欢的浏览器扩展是什么?它完成什么任务?

三、扩展的安装与加载流程:npm build → Load Unpacked / Reload

在动手写代码前,先走一遍"编写并部署浏览器扩展"的完整流程。各浏览器管理这一过程的方式略有差异,但 Chrome、Firefox、Edge 的流程本质相同,原文档以 Edge 为例:

  1. npm build 构建扩展(starter 代码库中对应的实际脚本是 npm run build,见下文 package.jsonscripts.build: "webpack");
  2. 点击浏览器右上角的 ... 图标,进入 Extensions(扩展)管理面板;
  3. 若是首次安装:选择 Load Unpacked,把构建产物文件夹(本项目为 /dist)加载进去;
  4. 若扩展已安装:代码改动后点击该扩展旁的 reload 重新加载即可。

✅ 注意区分:本流程针对你自己构建的扩展(开发者侧载)。若要安装各浏览器官方商店(如 Microsoft Edge Add-ons)已发布上架的扩展,则直接去对应商店搜索安装即可——这也正是文末"挑战"环节要做的事。

四、项目准备:一个展示区域碳足迹的扩展

本项目的产品形态是一个区域碳足迹扩展:显示你所在地区的能源使用量与能源来源。扩展内置一个表单,用于收集访问 CO2 Signal API 所需的 API 密钥,并在结果界面输出该地区的碳使用数据。

所需资源清单(原文档完整继承)

  • API 密钥:CO2 Signal 的 API key——在其官网页面输入邮箱即可收到密钥邮件;
  • 区域代码:对应 Electricity Map 的区域编码(Electricity Map 的 zones 接口提供全集;例如波士顿使用 US-NEISO);
  • starter 代码:仓库中的 start 文件夹 即课程起点,后续所有代码都在这个文件夹内完成;
  • NPM:Node 的包管理工具,需本地安装;它会按 package.json 中列出的依赖安装好构建所需的 Web 资产。

✅ 实操提示:拿到 API key 和区域代码后先记下来,后续会反复用到。安全上切勿把密钥提交进代码仓库。

代码库结构:dist 与 src 的分工

原文档给出的目录树如下(dist 放构建产物与默认配置,src 放你书写的源码):

dist
    -|manifest.json (defaults set here)   # 扩展默认配置
    -|index.html (front-end HTML markup)  # 前端 HTML 标记
    -|background.js (background JS)       # 后台脚本
    -|main.js (built JS)                  # Webpack 打包后的 JS
src
    -|index.js (your JS code goes here)   # 你的 JS 代码写在这里

结合仓库实际文件可以进一步确认每个角色的实现事实:

dist/manifest.json 是 Manifest V3 清单,决定了扩展的身份、权限与入口(manifest.json 原文如下):

{
	"manifest_version": 3,
	"name": "My Carbon Trigger",
	"version": "0.1.0",
	"host_permissions": ["<all_urls>"],
	"background": {
		"service_worker": "background.js"
	},
	"action": {
		"default_popup": "index.html"
	}
}
  • "manifest_version": 3:使用 MV3,后台脚本以 service_worker 形式声明(background.js);
  • "action.default_popup": "index.html":点击扩展图标时弹出的就是 dist/index.html,这正是我们本阶段要填充表单与结果区的文件;
  • "host_permissions": ["<all_urls>"]:为后续调用外部 API 预留的宿主权限。

dist/index.html 目前是带占位注释的骨架(index.html):

<body class="container">
	<img alt="plants and people" src="images/plants-people.png" />
	<div>
		<h1>Welcome to Your Personal Carbon Trigger!</h1>
	</div>
	<!--form area-->      <!-- 本阶段要填充的表单区域 -->
	<!--result area-->    <!-- 本阶段要填充的结果区域 -->
	<script src="main.js"></script>
</body>

页面通过 styles.css 引入基础样式(基于 Basic.css 的变量体系,支持 prefers-color-scheme: dark 暗色模式,见 styles.css),并以 <script src="main.js"> 挂载打包产物。

src/index.js 是带编号注释的脚手架(index.js),为后续课程的实现排好了 1–6 的落点:1 表单字段选择器、2 设置监听并启动应用、3 初始检查、4 处理表单提交、5 设置用户的 API key 与区域、6 调用 API——本阶段(第一部分)先只动 HTML,JS 逻辑留到后续课程。

五、构建扩展的 HTML:两个屏幕(配置表单 + 结果区)

这个扩展有两个界面:第一屏收集 API 密钥与区域代码,第二屏输出该区域的碳使用数据。

扩展第一屏:收集 Region Name 与 API Key 的配置表单

扩展第二屏:输出 Region、Carbon Usage 与 Fossil Fuel Percentage 的结果界面

现在动手:在 /dist 文件夹的 index.html 中,在 <!--form area--> 处填入表单区域(原文档完整代码):

<form class="form-data" autocomplete="on">
	<div>
		<h2>New? Add your Information</h2>
	</div>
	<div>
		<label>Region Name</label>
		<input type="text" required class="region-name" />
	</div>
	<div>
		<label>Your API Key from tmrow</label>
		<input type="text" required class="api-key" />
	</div>
	<button class="search-btn">Submit</button>
</form>

这个表单的用途是:让用户填入保存的信息,并将它们写入本地存储(localStorage)。结构要点:

  • class="form-data":整个表单的容器类,后续 JS 用它绑定 submit 事件;
  • class="region-name"class="api-key":两个必填输入框(required),JS 通过这两个类名取值并存入 localStorage;
  • autocomplete="on":允许浏览器自动填充,改善首次配置体验;
  • class="search-btn":提交按钮。

接着,在表单下方添加结果区域(原文档完整代码):

<div class="result">
	<div class="loading">loading...</div>
	<div class="errors"></div>
	<div class="data"></div>
	<div class="result-container">
		<p><strong>Region: </strong><span class="my-region"></span></p>
		<p><strong>Carbon Usage: </strong><span class="carbon-usage"></span></p>
		<p><strong>Fossil Fuel Percentage: </strong><span class="fossil-fuel"></span></p>
	</div>
	<button class="clear-btn">Change region</button>
</div>

各区域的职责(结合仓库最终实现印证):

  • loading:请求 API 期间的加载提示;
  • errors:API 失败或数据无效时显示错误信息;
  • data:保留原始数据用于开发调试;
  • result-container:格式化展示碳数据;其中 my-regioncarbon-usagefossil-fuel 三个 span 就是后续 JS 填充文本的目标节点;
  • clear-btn("Change region"):允许用户更换区域、重新配置扩展。

可以对照 solution 目录中的成品构建产物 验证这些类名正是后续 JS 的查询目标:实现中通过 document.querySelector(".form-data").region-name.api-key.errors.loading.result-container.carbon-usage.fossil-fuel.my-region.clear-btn 分别取到上述节点,把 apiKeyregion 写入 localStorage,随后以 auth-token 请求头调用 CO2 Signal 的 /v1/latest 接口,取回 carbonIntensity(单位:克 CO2/千瓦时)与 fossilFuelPercentage(化石燃料占比)后填入对应 span,并用 display 样式在 loading / 表单 / 结果三种状态间切换。

六、构建链:npm install 与 Webpack 打包

HTML 写好后,回到终端完成本阶段的收尾——安装依赖并构建:

npm install

该命令使用 Node 的包管理器 npm,按 package.json 安装扩展构建流程所需的依赖。从仓库的 package.json 可以确认其具体内容:

{
	"name": "carbon-trigger-extension",
	"engines": {
		"npm": ">=9.0.0",
		"node": ">=18.0.0"
	},
	"scripts": {
		"test": "echo \"Error: no test specified\" && exit 1",
		"watch": "webpack --watch",
		"build": "webpack"
	},
	"devDependencies": {
		"webpack": "^5.105.0",
		"webpack-cli": "^5.1.4"
	},
	"dependencies": {
		"axios": "^1.15.0"
	}
}
  • webpack + webpack-cli 是构建工具链:Webpack 是一个 bundler,负责控制编译与打包;
  • axios 是运行期依赖,供后续课程发起 API 请求使用(starter 的 main.js 目前为空文件,构建后才会被填充——对照 solution 的构建产物 可以看到 axios 库已被完整打进 bundle,这正是"代码被捆绑(bundled)"的直观证据);
  • engines 声明了运行前提:Node >= 18、npm >= 9,环境不满足时 npm install 会直接报错;
  • scripts 中除 build: "webpack" 外还提供 watch: "webpack --watch"——开发时开启 watch 模式,src/ 下的改动会被自动重新打包,省去每次手动 build。

构建完成后:

npm run build

输出即 /dist/main.js。此时若把该扩展作为开发者扩展部署到 Edge,弹出窗口中表单就会以干净排版显示——本阶段(第一部分)到此完成,后续课程将在此基础上加入交互逻辑。

从源码结构看:扩展图标"能量点"系统

作为对整体架构的预告,starter 的 background.js 展示了 MV3 service worker 如何与弹窗页面协作:它监听 chrome.runtime.onMessage 事件,当收到 action === 'updateIcon' 的消息时,调用 drawIcon 函数,用 OffscreenCanvas 画布绘制一个 100×100 的彩色圆点并 getImageData 后通过 chrome.action.setIcon 更新扩展栏图标颜色。solution 的构建产物中可以看到,carbonIntensity 会先按 [0, 150, 600, 750, 800] 分档取最近值,再映射到 #2AA364(绿)→ #381D02(深褐)的色阶——这就是浏览器扩展栏上那枚"碳强度指示点"(灵感来自 Energy Lollipop 扩展)。理解这条"popup 发消息 → service worker 改图标"的调用链,是理解后续课程背景脚本(Part 3)的钥匙。

七、练习、挑战与自我提升

课后挑战(原文档 🚀 Challenge):去浏览器扩展商店浏览,挑选一个扩展安装到你的浏览器上,然后设法"拆解"它的文件。你能发现什么?——商店扩展的解包结构与本课程的 manifest.json + 打包 JS 结构如出一辙,这是把课堂知识落到实处的最好方式。

课后作业:本课的正式作业是 Restyle your extension,要求你在保持可用性的前提下为扩展设计配色、字体与布局,用 npm run build + 重新加载的方式测试表单、加载、结果、错误各视觉状态,并按评分表(视觉设计 / 功能性 / 代码质量 / 可访问性四个维度)自评。

复习与自学习:本课带我们回顾了一点浏览器历史。建议顺着这条线继续:阅读 Web 浏览器发展史、万维网(World Wide Web)的历史,以及 Sir Tim Berners-Lee 关于 Web 诞生 30 年的访谈,理解万维网先驱们当初如何构想着它的用途——这会让你在后续设计扩展功能时更有历史纵深。

可立即动手的清单(结合原文档与仓库):

  1. 打开浏览器的扩展管理页(如 edge://extensionschrome://extensions),开启开发者模式,清点你已安装的扩展;
  2. 在 DevTools 的 Network 面板里观察一次网页加载,验证"请求 → 响应 → 渲染"的链路;
  3. 按本文第五、六节完成 dist/index.html 的表单与结果区填写,跑通 npm installnpm run build 与 Load Unpacked 全流程;
  4. 对照 solution 的完整实现starter 的起点代码,逐行理解从脚手架到成品之间差了什么。
登录后查看全文
热门项目推荐
相关项目推荐