Carbon Trigger 浏览器扩展完整指南:基于 CO2 Signal API 追踪区域碳强度的安装、构建与源码解析
导读
本文围绕 Web-Dev-For-Beginners 课程「浏览器扩展」模块的解决方案代码(5-browser-extension/solution),完整讲解如何构建并部署一个名为 Carbon Trigger 的浏览器扩展:它通过 tmrow 出品的 CO2 Signal API 读取用户所在区域的实时用电碳排放强度,并以浏览器工具栏中的「彩色圆点」给出直观提醒,帮助用户在用电高峰决定是否执行洗衣、烘干等高耗能活动。读完本文,你将掌握该扩展从 npm install、webpack 打包、Edge「加载解压缩的扩展」安装,到获取 API Key、填写区域代码以及理解整套前端数据流的完整链路。
项目定位:一个驻留在浏览器里的碳足迹提醒器
Carbon Trigger 的定位非常明确:扩展(extension)本质上是一个针对单一任务高度定制、运行在浏览器环境里的"迷你网站"。它会在用户输入 API Key 与区域代码后,随时按需(ad hoc)查询该区域的实时电力碳排放强度,将"此刻是否适合执行高耗能活动"的信号直接放进浏览器,影响用户的用电决策。例如:当区域用电负荷高、碳强度大时,延迟使用滚筒烘干机这类高碳活动就是更环保的选择。
该扩展在课程中同时覆盖 Microsoft Edge、Chrome 等 Chromium 内核浏览器(Edge 新版基于 Chromium,因此可以复用 chrome.* API,这也是本项目源码中出现 chrome.runtime.sendMessage 的原因)。"彩色圆点"这一图标交互概念源自加州排放监测的 Energy Lollipop 扩展,而整个 Web Carbon Trigger 项目创意则由 Microsoft Green Cloud Advocacy 团队提出。
环境准备与依赖清单
在构建前,需要确认本机满足以下条件(依据 solution/package.json 中声明的 engines 字段):
- Node.js:
>= 18.0.0 - npm:
>= 9.0.0
项目核心依赖只有两个运行时/构建工具(均可在 package.json 的 dependencies 与 devDependencies 中核对):
| 类型 | 包名 | 版本 | 作用 |
|---|---|---|---|
| dependencies | axios |
^1.15.0 |
发起 CO2 Signal API 请求 |
| devDependencies | webpack |
^5.105.4 |
模块打包 |
| devDependencies | webpack-cli |
^5.1.4 |
命令行调用 webpack |
package.json 暴露了两个脚本,构成后续构建的全部入口:
build:执行webpack,一次性的生产打包;watch:执行webpack --watch,开发期监听文件变更并自动重建。
安装依赖与 webpack 打包
拿到源码副本后,先在项目目录(即 5-browser-extension/solution/,课程练习版同理为 5-browser-extension/start/)安装所有依赖:
npm install
随后使用 webpack 完成扩展的打包构建:
npm run build
从安装说明可以看出,构建产物会输出到 dist 目录——后续在浏览器中"加载解压缩的扩展"时,选中的正是这个 dist 文件夹。开发阶段可使用 npm run watch,使每次修改源码后自动重新打包,省去手动重复执行 build。
在 Edge 中加载扩展(Load Unpacked)
将扩展安装到 Edge(适用于 Chromium 内核浏览器)的步骤如下:
- 点击浏览器右上角"三点"菜单,打开**扩展(Extensions)**面板;
- 开启"开发人员模式",选择加载解压缩的扩展(Load Unpacked);
- 在弹出的目录选择框中,定位到刚构建好的
dist文件夹; - 确认后扩展即被加载,工具栏出现 Carbon Trigger 图标。
需要提醒的是:每次执行 npm run build 重新打包后,都要回到扩展管理页重新加载(Reload)该扩展,新代码才会生效。
使用前的关键配置:API Key 与区域代码
扩展默认不会自动工作,首次使用前需要两项配置:
1. CO2 Signal API Key
在 CO2 Signal 官网页面(co2signal.com)的输入框中填写邮箱,即可通过邮件获取 API Key。该 Key 将作为请求头 auth-token 随 API 调用一并发送。
2. 区域代码(Region Code)
区域代码需与 Electricity Map(electricitymap.org)区域划分对应,可从其 zones 接口获取。例如美国波士顿区域使用 US-NEISO。不同国家/地区的代码格式不同,填写错误时扩展会在界面中提示数据不可用。
将这两项填入扩展表单后,表单会通过 localStorage 持久化保存(详见下文源码解析),此后每次打开扩展都会自动恢复并重新请求最新数据。
源码级拆解:数据请求 → 颜色映射 → 图标更新
解决方案的全部逻辑集中在 solution/src/index.js 一个文件中。整体数据流为:表单提交 → 写入 localStorage → axios 请求 CO2 Signal API → 校验并展示碳数据 → 计算颜色 → 通知后台脚本更新图标。
1. DOM 元素与状态管理
文件开头通过 document.querySelector 抓取表单字段与结果展示区域:
- 输入区:
.form-data(表单)、.region-name(区域)、.api-key(密钥); - 结果区:
.errors(错误提示)、.loading(加载态)、.result-container(结果容器)、.carbon-usage(碳强度)、.fossil-fuel(化石燃料占比)、.my-region(当前区域); - 操作:
.clear-btn(清除按钮)。
界面通过显隐切换(display: none/block)在"表单态 / 加载态 / 结果态"之间流转,配合错误信息实现完整的状态机。
2. displayCarbonUsage:携带认证的 API 请求
核心函数 displayCarbonUsage(apiKey, region) 使用 axios 向 CO2 Signal 最新数据端点发起 GET 请求(源码 L34-L68):
await axios
.get('https://api.co2signal.com/v1/latest', {
params: { countryCode: region },
headers: { 'auth-token': apiKey },
})
可见认证方式为:请求参数携带 countryCode(区域代码),请求头携带 auth-token(API Key)。拿到响应后,代码先做数据校验——若 carbonIntensity(碳强度)或 fossilFuelPercentage(化石燃料发电占比)缺失,则抛出错误并进入兜底逻辑;校验通过后:
CO2 = Math.floor(data.carbonIntensity),交给颜色计算函数;- 结果区展示三行信息:
- 区域代码(如
US-NEISO); Math.round(carbonIntensity) + ' grams (grams C02 emitted per kilowatt hour)'—— 每千瓦时排放的二氧化碳克数;fossilFuelPercentage.toFixed(2) + '%'—— 发电中化石燃料所占百分比(保留两位小数);
- 区域代码(如
- 隐藏加载态与表单,展示结果容器。
若请求失败(网络错误、区域代码无效、数据缺失等),函数会打印 console.warn,隐藏加载态与结果区,并在 .errors 中显示 'Sorry, data unavailable for the selected region.' 提示。
3. calculateColor:把碳强度翻译成视觉颜色
颜色映射是 Carbon Trigger 最有辨识度的功能(源码 L17-L32)。其内部维护两个基准数组:
let co2Scale = [0, 150, 600, 750, 800];
let colors = ['#2AA364', '#F5EB4D', '#9E4229', '#381D02', '#381D02'];
映射算法分为两步:
- 对
co2Scale按"与当前值的绝对距离"排序,取最接近的刻度值closestNum; - 借助
findIndex找到数组中第一个大于该刻度值的元素下标scaleIndex,再以该下标从colors中取出对应颜色。
随后通过 chrome.runtime.sendMessage({ action: 'updateIcon', value: { color: closestColor } }) 把颜色消息发给后台脚本。课程 3-background-tasks-and-performance 对色阶含义给出如下概括,便于开发者把数值读成环境语义:
- 0–150:绿色(清洁能源,适合执行耗电活动);
- 150–600:黄色(中等,需留意);
- 600–750:橙色(高碳强度);
- 750 以上:深棕(碳排放很高,应推迟高耗能活动)。
对应地,代码中的颜色也从绿色 #2AA364(干净)一路过渡到深棕 #381D02(高碳)。需要注意的是,该函数在实现上会直接对 co2Scale 数组执行排序(就地修改原数组),理解此细节有助于阅读后续 findIndex 的取值逻辑。
4. 后台脚本:接收消息并动态绘制图标
src/index.js 中 chrome.runtime.sendMessage 的接收方是扩展后台脚本。chrome.runtime API 负责扩展各上下文之间的消息传递、后台页面管理与生命周期事件响应。课程第 3 部分说明,需在构建产物 dist/background.js 中补充消息监听器与图标绘制函数(可参阅 课程文档 中的代码),核心要点为:
- 用
chrome.runtime.onMessage.addListener监听updateIcon消息; - 调用
chrome.action.setIcon({ imageData })更新工具栏图标; - 使用
OffscreenCanvas(离屏画布)+ Canvas 2D 上下文绘制一个纯色圆点再取imageData,以此避免阻塞 UI,属于后台性能优化手段。
5. 本地持久化与初始化流程
代码将"表单提交、首次初始化、清除重置"串成完整闭环:
setUpUser(apiKey, region)(L72-L80):把apiKey、region写入localStorage,显示加载态并立即发起首次请求;- 表单提交监听:
form.addEventListener('submit', handleSubmit),提交时调用setUpUser(apiKey.value, region.value); init()(L89-L116):启动时先把图标设为默认绿色(让用户从安装起就能感知扩展处于工作状态),随后读取localStorage——若apiKey或region缺失则显示表单,否则隐藏表单并直接用已存值调取数据;reset()(L118-L123):点击清除按钮时仅移除region键,再执行init()回到表单态;- 启动入口:文件末尾依次注册
submit与click事件监听并调用init()启动应用。
这套流程体现了扩展开发的常见模式:localStorage 记忆用户配置 + 启动时自动恢复 + 失败回退到表单,值得作为其它扩展的表单/存储参考。
测试与扩展学习路径
构建并加载完成后,可这样验证扩展是否工作正常:
- 在扩展表单中填入已获取的 API Key 与合法区域代码(如
US-NEISO)并提交; - 观察工具栏圆点颜色是否随区域碳数据变化,结果区是否显示"克 CO₂/kWh"与"化石燃料占比";
- 关闭并重新打开浏览器/扩展,确认配置被
localStorage记住且自动刷新数据; - 使用错误区域代码,验证错误提示分支是否生效。
如果你想从零跟随课程动手实现而非直接使用最终代码,可参考同模块的 starter 代码(其 src/index.js 仅保留占位注释,需自行补全);课程的三个递进单元位于:
- 1-about-browsers:浏览器工作原理与扩展部署
- 2-forms-browsers-local-storage:表单、浏览器与本地存储
- 3-background-tasks-and-performance:后台任务与性能优化
小结
Carbon Trigger 的解决方案代码以约 130 行的单一 index.js 示范了浏览器扩展开发中的高复用骨架:表单校验、localStorage 持久化、带认证的外部 API 调用、数据校验兜底、数值到颜色的可视化映射、消息驱动的图标更新,再配合 webpack 打包与 Edge「加载解压缩的扩展」即可快速落地。这套模式同样可复用到空气质量、电价、疫情等一切"按区域查询、按状态变色"的提醒类扩展中,是入门扩展开发的理想范本。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00

