uBlock uBOLite(MV3)CodeMirror 6 打包重建指南:构建步骤、产物打包与源码消费链
本篇以 platform/mv3/extension/lib/codemirror/README.md 为核心,讲解如何为 uBlock 的 MV3 版本 uBOLite 重建唯一的代码编辑器依赖 cm6.bundle.ubol.min.js:文中完整保留了官方 README 的 submodule 初始化与 npm 构建六步流程,并结合 tools/make-mv3.sh、platform/mv3/extension/dashboard.html 及各编辑器模块源码,说明该产物在打包阶段如何被复制进最终扩展包、在运行时又被哪些功能消费。读完后你可以独立完成 bundle 重建,并理解它在整条 MV3 构建链路中的位置。
一、这份 README 解决什么问题:cm6.bundle.ubol.min.js 的来源
platform/mv3/extension/lib/codemirror/README.md 的正文只围绕一件事:说明 platform/mv3/extension/lib/codemirror/ 目录下的 cm6.bundle.ubol.min.js 这个文件是从哪里来的、如何重新构建它。该目录当前包含三类内容:
README.md:即这份构建说明;codemirror.LICENSE:CodeMirror 的 MIT 许可证(Copyright 2018–2021,Marijn Haverbeke and others,见 codemirror.LICENSE);codemirror-ubol/:Git submodule 挂载点。
关键点在于 codemirror-ubol/ 目录在浅层检出时是空的。它对应 .gitmodules 中定义的子模块:
[submodule "platform/mv3/extension/lib/codemirror/codemirror-ubol"]
path = platform/mv3/extension/lib/codemirror/codemirror-ubol
url = codemirror-ubol(作者的定制仓库)
README 进一步说明:进入该目录后,你所在的仓库是一个定制化的 fork,其上游是 RPGillespie6/codemirror-quickstart 项目(CodeMirror 6 的官方快速入门/打包工程)。也就是说,uBlock 并不是直接使用官方 CodeMirror 6 的发布产物,而是维护了一个 fork,以便按自身需求裁剪与封装出单文件的 cm6.bundle.ubol.min.js。
从源码结构看,这种“单文件 bundle”的用法与主扩展形成鲜明对比:主扩展(uBlock Origin)的页面如 src/1p-filters.html、src/asset-viewer.html 加载的是 CodeMirror 5 的多文件结构(lib/codemirror/lib/codemirror.js 加 comment、fold、search、hint 等十余个 addon 脚本);而 MV3 的 uBOLite 则只加载一个预打包的 CM6 文件。可以推断,MV3 平台对脚本加载方式的限制促使 uBOLite 采用了“一次打包、单文件引入”的策略,这正是本 README 所描述的 bundle 存在的意义。
二、重建 cm6.bundle.ubol.min.js:官方六步流程
以下命令序列完整继承自原 README(“command line from repo root”,即从仓库根目录开始执行):
# 1. 从仓库根目录初始化 codemirror-ubol 子模块
git submodule init platform/mv3/extension/lib/codemirror/codemirror-ubol
# 2. 进入子模块目录
cd platform/mv3/extension/lib/codemirror/codemirror-ubol/
# (此时已进入从 codemirror-quickstart fork 出的定制仓库)
# 3. 安装依赖
npm install
# 4. 执行构建
npm run build
构建完成后的两个结果,README 中均有明确表述:
cm6.bundle.ubol.min.js会出现在子模块的dist目录中(即platform/mv3/extension/lib/codemirror/codemirror-ubol/dist/);- 该文件正是当前目录(
platform/mv3/extension/lib/codemirror/)下同名文件的来源——即 MV3 扩展实际引用的 bundle 由这次构建产出。
补充两点与仓库上下文一致的说明:
- platform/mv3/README.md 给出的完整 MV3 构建流程中,
git submodule init之后紧跟git submodule update才会真正拉取子模块内容;若你只想重建 bundle 而不做完整扩展构建,需自行确保子模块工作区已检出后再执行npm install/npm run build。 - 由于
codemirror-ubol是 fork 自 codemirror-quickstart 的工程,npm run build走的是其 quickstart 构建脚本,产物路径固定为dist/,这一点与后续打包脚本的预期路径严格对应(见下节)。
三、产物去向:tools/make-mv3.sh 如何把它打进最终扩展包
重建出的 bundle 并非直接可用,而是由 MV3 打包脚本消费。tools/make-mv3.sh 中有一段专门的库文件复制逻辑:
# Libraries
mkdir -p "$UBOL_DIR"/lib/codemirror
cp platform/mv3/extension/lib/codemirror/* \
"$UBOL_DIR"/lib/codemirror/ 2>/dev/null || :
cp platform/mv3/extension/lib/codemirror/codemirror-ubol/dist/cm6.bundle.ubol.min.js \
"$UBOL_DIR"/lib/codemirror/
cp platform/mv3/extension/lib/codemirror/codemirror.LICENSE \
"$UBOL_DIR"/lib/codemirror/
cp platform/mv3/extension/lib/codemirror/codemirror-ubol/LICENSE \
"$UBOL_DIR"/lib/codemirror/codemirror-quickstart.LICENSE
这段代码印证了 README 所说的构建链路:
- 打包时,脚本强制从子模块的
dist/目录复制cm6.bundle.ubol.min.js到最终包的lib/codemirror/(第 120–121 行)。注意该复制行没有|| :容错后缀——若 bundle 不存在,构建会直接失败,这正是“必须先成功执行npm run build”的硬性约束; - 许可证文件同步复制:CodeMirror 本体的 codemirror.LICENSE 保留原名,而 fork 仓库自带的
LICENSE则改名为codemirror-quickstart.LICENSE,区分上游 quickstart 工程的版权说明; - 按 platform/mv3/README.md,最终扩展包落在
dist/build/uBOLite.[platform](platform 为 chromium、edge、firefox 或 safari),bundle 随包内lib/codemirror/一同分发。
四、运行时消费:self.cm6 全局 API 与它的调用方
platform/mv3/extension/dashboard.html 在页面末尾以经典脚本方式加载 bundle,且先于所有业务模块脚本:
<script src="lib/codemirror/cm6.bundle.ubol.min.js"></script>
<script src="js/theme.js" type="module"></script>
<script src="js/dashboard.js" type="module"></script>
<script src="js/develop.js" type="module"></script>
由此可以推断,该 bundle 向全局暴露了一个封装对象 cm6,供 MV3 扩展各编辑器模块调用。仓库中实际消费它的主要模块有:
- platform/mv3/extension/js/develop.js:自定义过滤器编辑面板的核心。调用
cm6.createViewPanel()创建 I/O 与摘要面板,cm6.createEditorView(viewConfig, ...)创建编辑器视图,并用cm6.foldAll(view)、cm6.resetUndoRedo(view)、cm6.toggleReadOnly(view, ...)管理折叠、撤销历史与只读状态;错误提示则通过cm6.lineErrorClear()与cm6.spanErrorClear()清理; - platform/mv3/extension/js/filter-editor.js:网络过滤器编辑器,同样依赖
cm6.createViewPanel()/cm6.createEditorView()/cm6.resetUndoRedo(); - platform/mv3/extension/js/dnr-editor.js:声明式网络请求规则编辑器,用
cm6.lineErrorAdd()、cm6.spanErrorAdd()标注坏规则,并用cm6.findAll()做编辑器内检索; - platform/mv3/extension/js/rw-dnr-editor.js 与 platform/mv3/extension/js/mode-editor.js:分别是 read/write DNR 规则编辑器与模式编辑器,同样复用
createViewPanel、foldAll、lineErrorAdd等 API。
综合这些调用点,从源码结构看,这个定制化 bundle 并非 CodeMirror 6 的“原样打包”,而是叠加了一层 uBlock 专用封装:编辑器视图创建、工具面板、错误行/片段高亮、全文查找、折叠与撤销历史重置等能力都被收敛进 cm6 命名空间,供 MV3 侧五个编辑器页面以统一接口使用。这也解释了为什么上游是 quickstart 工程的 fork——官方 quickstart 只负责把 CM6 打成 bundle,而 uBlock 需要的错误标注与面板集成必须在其构建基础上定制。
五、验证与排查建议
执行 README 流程后,可按以下顺序验证产物与链路是否完整:
- 确认
platform/mv3/extension/lib/codemirror/codemirror-ubol/子模块工作区非空(空目录即git submodule init未生效或未git submodule update); - 确认
platform/mv3/extension/lib/codemirror/codemirror-ubol/dist/cm6.bundle.ubol.min.js已生成——这是 tools/make-mv3.sh 第 120–121 行复制动作的源文件,缺失会导致打包失败; - 如需完整走通 MV3 构建(
make mv3-[platform]),按 platform/mv3/README.md 的前提准备环境:完整流程还要求 Node.js 17.5.0 及以上,且构建期间会从远程服务器下载过滤列表数据; - 注意不要混淆两套 CodeMirror:
src/lib/codemirror/下是主扩展使用的 CodeMirror 5 多文件库(供 src/1p-filters.html、src/advanced-settings.html、src/code-viewer.html 等页面使用),与本 README 讨论的 MV3 侧 CM6 单文件 bundle 相互独立,重建 bundle 不会也不应影响前者。
小结
这份简短的 README 定义了 uBOLite(MV3)编辑器体验的“单一依赖”:cm6.bundle.ubol.min.js 由 codemirror-ubol 子模块(codemirror-quickstart 的定制 fork)经 npm install + npm run build 产出,再由 tools/make-mv3.sh 连同两份许可证文件复制进各平台最终包,运行时由 dashboard.html 加载,并通过全局 cm6 API 支撑自定义过滤器、动态网络规则等多个编辑器界面。掌握这六步构建命令与上述打包、消费链路,即可独立完成该 bundle 的重建与验证。
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