uBlock Origin MV3 构建指南:从零构建 uBO Lite(uBOLite)扩展包的完整流程
本文以 platform/mv3/README.md 为蓝本,系统讲解 uBlock Origin 仓库中 MV3 分支的构建体系:如何在 Linux 环境下通过 Makefile 与 tools/make-mv3.sh 为 Chromium、Edge、Firefox、Safari 四个平台分别产出 uBOLite 扩展包,并深入解析其底层机制——过滤列表如何被 make-rulesets.js 转换为声明式网络请求(Declarative Net Request, DNR)规则集、本地缓存如何避免重复抓取远程列表,以及构建日志的生成与诊断方法。读完后你将能够独立完成一次完整的 MV3 构建、定位构建失败原因,并理解产出包内部各目录的职责。
一、构建前提:为什么 MV3 构建是独立流程
uBlock Origin 主线(MV2 形态)的构建目标位于 Makefile 的 chromium、firefox、opera 等条目中;而 MV3 形态(对外称 uBO Lite,简称 uBOLite)走的是另一套独立目标:
mv3-chromium、mv3-firefox、mv3-edge、mv3-safari—— 对应 platform/mv3/README.md 中提到的make mv3-[platform];- 每个目标都依赖
ubol-codemirror目标,该目标先构建 platform/mv3/extension/lib/codemirror/codemirror-ubol 下的 CodeMirror 6 自定义 bundle(cm6.bundle.ubol.min.js),因为 MV3 扩展的规则编辑界面依赖它; - 各平台目标的依赖列表中显式包含
$(mv3-data)与dist/build/mv3-data,即 Makefile 会把过滤列表缓存目录纳入增量构建的依赖计算——缓存中的列表更新后,会重新触发规则集生成。
构建脚本本身假设运行在 Linux 环境(tools/make-mv3.sh 文件头部注释即写明 "This script assumes a linux environment"),并且要求 Node.js 17.5.0 及以上版本——这一约束同样固化在 platform/mv3/package.json 的 engines 字段中:
{
"engines": {
"node": ">=17.5.0"
},
"type": "module"
}
Node 17.5.0 是首个稳定提供全局 fetch 的版本,而 make-rulesets.js 的抓取逻辑正依赖原生 fetch(见下文第三节)。
二、标准构建步骤(完整继承自官方文档)
以下步骤逐条对应 platform/mv3/README.md 的官方说明,适用于一个干净的 Linux 环境:
# 1. 打开 Bash 控制台
# 2. 克隆仓库
git clone https://github.com/gorhill/uBlock.git
# 3. 进入仓库
cd uBlock
# 4. 初始化子模块
git submodule init
# 5. 更新子模块
git submodule update
# 6. 执行 MV3 构建,[platform] 取值为 chromium / edge / firefox / safari 之一
make mv3-[platform]
第 6 步会完整地构建 uBOLite,并在构建过程中从各远程服务器下载过滤列表(uAssets、EasyList、EasyPrivacy 等)。构建完成后,各平台的扩展包分别落在:
| 平台 | 产物路径 |
|---|---|
| Chromium | dist/build/uBOLite.chromium |
| Edge | dist/build/uBOLite.edge |
| Firefox | dist/build/uBOLite.firefox |
| Safari | dist/build/uBOLite.safari |
这些产物路径与 tools/make-mv3.sh 中 UBOL_DIR="dist/build/uBOLite.$PLATFORM" 的定义完全一致。
此外还有两点官方文档明确说明、值得强调的运维细节:
- 列表缓存目录:
dist/build/mv3-data会缓存从远程服务器抓取的过滤列表数据,避免重复执行构建命令时反复抓取远程资源。如果需要用最新版列表重新构建,先执行make cleanassets清掉本地缓存。对照 Makefile 可以看到该目标的具体行为是删除dist/build/mv3-data与dist/build/uAssets两个目录。 - 构建日志:
dist/build/uBOLite.[platform]/log.txt记录了构建过程发生的一切,是排查构建失败的第一入口(其生成机制见第三节)。
三、构建流程深挖:make-mv3.sh 的三段式工作流
官方文档指出,实现整个构建过程的 Makefile 条目是 tools/make-mv3.sh [platform]。该 Bash 脚本的职责是把 uBlock Origin 主线分支的文件与 MV3 专属分支的文件拷贝合并到一个文件夹,这个文件夹就是最终的扩展包。通读 tools/make-mv3.sh,可以将其工作流拆解为四个阶段:
3.1 参数解析与平台选择
脚本通过 case 解析命令行参数:chromium/firefox/edge/safari 决定 PLATFORM,full 或形如 1.2.3 的版本号会置 FULL=yes(构建可发布的 zip/xpi 包),before=<dir> 则用于规则 ID 回收(见 3.4)。值得注意的是,Edge 平台实际复用 platform/mv3/chromium/manifest.json(MANIFEST_DIR="chromium"),因为 Edge 本质上是 Chromium 的 DNR 方言。
3.2 文件合并:主线与 MV3 分支的拼装
脚本先清空并重建 dist/build/uBOLite.$PLATFORM,然后分两批拷贝:
- 通用文件(来自
src/,即主线代码):CSS 主题与字体(common.css、dashboard-common.css、fa-icons.css等)、核心 JS(arglist-parser.js、i18n.js、static-filtering-parser.js、redirect-resources.js等)、flags-of-the-world国旗图片、LICENSE.txt; - MV3 专属文件(来自 platform/mv3/extension 与平台子目录):各页面 HTML、platform/mv3/extension/css 下的界面样式、platform/mv3/extension/js 下的全部脚本(包含
dnr-editor.js、filter-manager.js、ruleset-manager.js等 MV3 特有模块)、platform/mv3/extension/_locales 下的 70 余种语言包,以及平台补丁文件(如ext-compat.js、ext-offscreen.js、css-api.js)。
随后拷贝第三方库:CodeMirror、csstree、s14e-serializer 等,写入 lib/ 目录。
3.3 规则集生成:从过滤列表到 DNR 规则
这是整个构建的核心。脚本把 platform/mv3 目录下的构建资产(rulesets.json、make-rulesets.js、salvage-ruleids.mjs)、扩展内的解析模块(ubo-parser.js、utils.js、static-dnr-filtering.js 等,以及 platform/mv3/extension/js/offscreen 下的 offscreen 处理模块)汇集到一个临时构建目录,然后执行:
node --no-warnings make-rulesets.js output="<扩展包目录>" platform="<平台>"
make-rulesets.js(约 1246 行)完成了文档所述"将过滤列表转换为声明式可用的各类规则集"的工作,其关键实现要点如下:
- 列表抓取与本地缓存:
fetchText()先尝试从<输出目录>/../mv3-data(即dist/build/mv3-data)读取以 URL 转写为文件名的缓存,命中则直接使用;未命中才发起远程fetch,成功后写回缓存文件。这正是官方文档强调mv3-data缓存目录的原因,也解释了为什么make cleanassets之后重建才能拿到最新列表。 - 规则集定义:
main()启动时解析 platform/mv3/rulesets.json(656 行、约几十个条目),逐项调用rulesetFromURLs()。每条规则集是一个声明式对象,核心字段包括:id/name/group:规则集标识、显示名与分组(default、malware、ads、privacy、annoyances、regions等);enabled:默认启用状态;trusted:标记为可信列表(可生成更强力的规则);urls:列表源地址,通常指向 uAssets 的 GitHub Pages 或各社区列表;excludedPlatforms:如pgl、ublock-badware等条目显式排除了safari平台,构建时会被跳过(if ( ruleset.excludedPlatforms?.includes(platform) ) { continue; });lang/tags/parent/homeURL:区域列表的语言代码、检索标签、父级分组及来源主页。
- 规则分类统计:每条列表会被解析为网络规则,并按类型计数——普通规则、正则规则、removeparam(展开处理)、redirect、modifyHeaders、strictblock、urlskip,以及被丢弃/拒绝的规则数,全部记入
ruleset-details.json; - cosmetic 过滤器的脚本化:由于 MV3 的 service worker 架构无法注入页面 CSS 规则,cosmetic 过滤器被编译为 CSS 脚本(
make-cosmetic-filters.js、make-scriptlets.js,模板见 platform/mv3/scriptlets),经 offscreen 文档处理,统计信息写入scriptlet-details.json; - 产物落盘与 manifest 打补丁:
main()末尾将每个规则集写为/rulesets/main/<id>.json,汇总注册到ruleResources;随后回写扩展包内的 manifest.json——填充declarative_net_request.rule_resources(源模板中该数组为空占位,由构建期注入)、追加重定向资源到web_accessible_resources,并用当前 UTC 时间生成形如2026.903.1530(年月.日时.分秒)的版本号。源 manifest 还要求minimum_chrome_version: "122.0"、以"service_worker": "/js/background.js"的 module 类型运行后台逻辑,权限包含declarativeNetRequest、offscreen、scripting等。 - 日志输出:脚本临时接管
console.log,把所有输出缓冲到stdOutput,最后一次性写入<输出目录>/log.txt——这正是官方文档中dist/build/uBOLite.[platform]/log.txt的由来。若某条日志以!!!开头,会同时打印到终端,通常提示构建中出现异常。
3.4 本地构建、发布打包与平台差异
tools/make-mv3.sh 的收尾阶段还有几处与日常开发直接相关的行为:
- 本地构建默认开启 DNR 调试:当不带版本号参数(即普通
make mv3-[platform])时,脚本用jq向 manifest 的permissions追加declarativeNetRequestFeedback(用于在开发者工具中查看 DNR 规则匹配),Firefox 平台还会把扩展 ID 改写为uBOLite.dev@raymondhill.net以区分正式包; - 正式发布模式:传入版本号(如
make mv3-chromium调用链中的full/1.0.0参数)会触发FULL=yes,删除rulesets/debug目录、把版本写入 manifest,最终打包为dist/build/uBOLite_<版本>.<平台>.zip(Firefox 为.xpi); - Edge 兼容性修正:Edge 要求声明式规则集放在包根目录,脚本会把
rulesets/main/*移到包根并运行 platform/mv3/edge/patch-extension.js;Safari 则统一交由 platform/mv3/safari/patch-extension.js 做合规性修补; - 规则 ID 回收:若指定
before=<旧包目录>,会执行 salvage-ruleids.mjs,在新旧规则集之间比对并尽量保留旧规则 ID,以最小化更新时 DNR 规则集的 diff 体积——从源码结构看,这对商店分发场景下的更新效率有直接意义。
四、构建产物结构速览
一次 make mv3-chromium 之后,dist/build/uBOLite.chromium 内的关键布局为:
- 扩展包根部的
manifest.json:构建期已注入rule_resources与版本号; rulesets/目录:全部最终规则集(main/<id>.json),以及ruleset-details.json、scriptlet-details.json、generic-details.json三份统计元数据,官方文档亦明确"All the final rulesets are present in thedist/build/uBOLite.[platform]/rulesets";rulesets/scripting/:由 cosmetic/scriptlet 过滤器编译出的注入脚本;js/、css/、img/、lib/、_locales/:扩展运行所需的全部前端资源;log.txt:本次构建的完整日志。
五、常见问题排查
- 构建报错 "fetch is not defined" 或网络类错误:确认 Node.js 版本 ≥ 17.5.0(platform/mv3/package.json 的硬性要求);远程列表抓取失败时先检查网络,或改用
make cleanassets清缓存后重试以获取最新列表。 - 想强制刷新过滤列表:
make cleanassets(删除dist/build/mv3-data与dist/build/uAssets)再重新执行make mv3-[platform]。 - 定位构建异常:优先阅读
dist/build/uBOLite.[platform]/log.txt;终端上以!!!开头的行是脚本主动放出的告警信息,可直接对应日志中的异常条目。 - 构建产物版本:普通本地构建的版本号是构建时刻的 UTC 时间戳;发布模式则使用传入的版本号并附带可安装压缩包。
六、小结
uBlock Origin 的 MV3 构建体系是一个典型的"声明式定义 + 构建期编译"流程:platform/mv3/rulesets.json 声明"要哪些列表",make-rulesets.js 负责"把列表变成浏览器原生 DNR 引擎可加载的规则集",tools/make-mv3.sh 与 Makefile 则负责"把主线与 MV3 分支拼成可安装的扩展包"。理解这条链路后,无论是复现官方构建、定制规则集来源,还是调试 DNR 规则匹配行为,都有了清晰的代码级抓手。
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 StartedRust0622
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