☰
browser-compat-data 数据迁移实战:从自动化脚本到全量合入的四步流程
2026/10/12 3:38:18 网站建设 项目流程
  • 数据集
  • 开发工具

【免费下载链接】browser-compat-data

Browser compatibility data for Web technologies as displayed on MDN

项目地址:https://gitcode.com/gh_mirrors/br/browser-compat-data
点击查看免费下载

@mdn/browser-compat-data(简称 BCD)是 MDN 维护的机器可读 Web 技术浏览器兼容性数据集,覆盖 Web API、CSS、JavaScript 等十余个领域。当项目需要对大规模 JSON 数据做结构性调整时,BCD 采用了一套类似数据库迁移(database migration)的流程:自动化脚本、配套测试、择机合入。本文基于 docs/migrations.md 的完整流程说明,结合仓库中真实存在的迁移脚本与测试用例,讲解如何为 BCD 编写、测试并执行一次数据迁移,读完你将掌握迁移脚本的命名规范、实现模式、测试方法与协作节奏。

一、什么时候该走迁移流程

BCD 的迁移流程针对的是适合自动化、影响大量文件、且是对既有数据进行修改的变更。与普通 PR 相比,这类变更如果靠人工逐个文件修改,会耗费大量时间,也容易出错。迁移流程的核心价值在于:

  • 自动化:把重复性修改写成脚本,一键跑完全仓库数据;
  • 可验证:脚本必须配有测试,证明它只做了预期修改、没有引入无关变更;
  • 低扰动:选择对他人影响最小的时机执行,避免与大量在审 PR 冲突。

如果变更规模较小,或者根本无法自动化,则不应该走迁移流程,直接开 pull request 或 issue 即可。例如给某个 API 修正一个版本号、给某个条目补充 notes,这类单点修改直接走常规 PR。

BCD 数据本身是高度结构化的 JSON,每个特性由__compat对象描述(详见 schemas/compat-data-schema.md),其中support字段按浏览器记录版本支持情况,status字段记录实验性、标准轨道与废弃状态。正是因为数据结构高度规整,才使得"全局改写"类迁移成为可能。

二、Step 1:在 issue 中宣布意图

一次规范的迁移从创建或复用 issue开始。这个 issue 是整个迁移过程的讨论与跟踪场所,需要做到:

  • 清晰描述变更内容:一次聚焦一类变更,不要混入多个不相关的改动;
  • 用 checklist 规划与跟踪进度:把"写脚本 → 测试 → 合并 → 执行 → 收尾"拆成可勾选的步骤;
  • 等待反馈:在进入下一步之前,给维护者留出评审与提出异议的时间。

三、Step 2:创建并测试迁移脚本

3.1 脚本目录与命名规范

迁移脚本统一放在 scripts/migrations 目录下,命名遵循###-<description>.js模式:

  • ###是迁移的顺序编号(如002、007、010);
  • <description>是对该迁移的简短描述(如remove-webview-flags)。

文档中提到的首个迁移是001-sort-features.js。当前仓库中保留的迁移脚本包括:

脚本配套测试迁移内容
002-remove-webview-flags.js002-remove-webview-flags.test.js移除 WebView Android 中带 flags 的支持语句
007-experimental-false.js007-experimental-false.test.js根据引擎支持数自动修正experimental状态
010-set-oculus-to-mirror.js—将缺失的oculus支持设为"mirror"
011-set-webview-ios-to-mirror.js—将缺失的webview_ios支持设为"mirror"
012-descriptions-to-md.js—将description中的<code>标签转换为 Markdown 反引号

3.2 脚本的通用实现骨架

从源码结构看,BCD 迁移脚本大多遵循同一套"reviver + 文件回写 + 递归遍历"模式。以 002-remove-webview-flags.js 为例:

// 核心转换函数:作为 JSON.parse 的 reviver,按 key 逐层处理 export const removeWebViewFlags = (key, value) => { if (key === '__compat') { if (value.support.webview_android !== undefined) { // 过滤掉带 flags 的语句,只保留无 flags 的版本 // ... if (result.length == 0) { value.support.webview_android = { version_added: false }; } else if (result.length == 1) { value.support.webview_android = result[0]; } else { value.support.webview_android = result; } } } return value; }; // 文件级处理:读文件 → JSON.parse(reviver) → 格式化 → 有变化才写回 export const fixWebViewFlags = (filename) => { let actual = fs.readFileSync(filename, 'utf-8').trim(); let expected = JSON.stringify( JSON.parse(actual, removeWebViewFlags), null, 2, ); if (IS_WINDOWS) { // 防止 Windows 上 git.core.autocrlf 造成的误判 actual = actual.replace(/\r/g, ''); expected = expected.replace(/\r/g, ''); } if (actual !== expected) { fs.writeFileSync(filename, expected + '\n', 'utf-8'); } };

其中几个关键设计值得迁移作者借鉴:

  • reviver 模式:利用JSON.parse(text, reviver)按 key 深度优先回调的特性,只对__compat节点动手,天然具备"只改数据不改结构"的语义;
  • 幂等与零改动跳过:actual !== expected时才写回文件,保证重复运行不会产生 diff、不会无谓触碰文件 mtime;
  • Windows 换行处理:借助 lint/utils.js 导出的IS_WINDOWS常量,避免 CRLF 造成的误判;
  • CLI 入口:脚本尾部用es-main判断是否被直接执行,支持传入单个路径,否则默认遍历dataFoldersMinusBrowsers(即api、css、html、http、javascript、manifests、mathml、mediatypes、svg、webassembly、webdriver、webextensions十二个数据目录,定义见 scripts/lib/data-folders.js):
if (esMain(import.meta)) { if (process.argv[2]) { load(process.argv[2]); } else { load(...dataFoldersMinusBrowsers); } }

3.3 迁移中的核心数据对象

迁移脚本操作的核心是__compat对象与support字段。理解它们的形态(详见 schemas/compat-data-schema.md)有助于编写正确的转换逻辑:

  • 每个特性的__compat下有一个必填的support对象,按浏览器标识符(如chrome、firefox、safari、webview_android等)记录支持情况;
  • 每个浏览器的值可以是一个simple_support_statement对象、多个语句组成的数组,或字符串"mirror"(表示自动镜像上游浏览器数据);
  • 语句对象中常见字段包括version_added(必填,可为版本字符串、false、≤版本或preview)、version_removed、prefix、alternative_name、flags、partial_implementation、notes等。

例如002-remove-webview-flags的语义是:WebView Android 中仅靠 flag 开启的功能不再值得记录(对应 README 中"removal of irrelevant flag data"的准则),因此把带flags的语句直接移除;若该浏览器只剩 flag 语句,则整条支持改写为version_added: false。

3.4 配套测试:证明只做该做的改动

脚本必须附带一个或多个测试,用于证明迁移"做出了描述的修改,且没有引入其他无关修改"。测试文件同样放在scripts/migrations/目录,命名为###-<description>.test.js,使用 Node.js 内置的node:test与node:assert/strict编写。

以 002-remove-webview-flags.test.js 为例,它通过"输入/期望输出"成对用例驱动:

const tests = [ { input: { __compat: { support: { webview_android: { version_added: '61', flags: [ { type: 'preference', name: '#service-worker-payment-apps', value_to_set: 'Enabled', }, ], }, }, // ... }, }, output: { __compat: { support: { webview_android: { version_added: false, }, }, // ... }, }, }, // 更多用例:无 flags 语句原样保留、数组语句中只保留无 flags 项等 ]; describe('migration scripts', () => { it('`removeWebViewFlags()` works correctly', () => { for (const test of tests) { const expected = test.output; const output = JSON.parse(JSON.stringify(test.input), removeWebViewFlags); assert.deepEqual(output, expected); } }); });

而 007-experimental-false.test.js 则展示了"基于真实 BCD 结构"的测试方式:构造api.fetch.__compat这样的嵌套数据,调用fixExperimental(bcd)后断言status.experimental是否被翻转。其四条用例恰好覆盖了迁移规则的边界:

  • Chrome + Firefox + Safari 三引擎都支持 →experimental从true改为false;
  • 只有 Chrome + Firefox 两引擎支持 → 同样改为false;
  • 仅 Chrome 一个引擎支持 → 保持experimental: true不变;
  • 桌面 Chrome/Safari 不支持但移动端chrome_android/safari_ios支持 → 视为多引擎,改为false。

对照 007-experimental-false.js 的源码可以确认其判定逻辑:先收集无flags、无prefix、无alternative_name且version_added存在、version_removed为空的支持语句所属浏览器,再映射到 Blink、Gecko、WebKit 三个引擎,最后统计命中引擎数,超过一个才把experimental置为false。这与 schemas/compat-data-schema.md 中对experimental字段"通常意味着被两个或更多浏览器引擎实现"的约定一致。

3.5 提交 PR 与审批要求

脚本和测试就绪后,需要开一个 pull request。该 PR 要被接受,必须经过至少一位 project owner 的评审与批准。Owner 的职责与审批边界见 GOVERNANCE.md:迁移脚本这类基础设施变更(非数据更新)只有 Owners 有权合并,这与"Peers 可合并 compat data PR、但不能合并 schema/linter/基础设施变更"的权限划分一致。

四、Step 3:执行迁移

迁移脚本被合并后,需要与一位 project owner 协调时间来完成迁移。执行时的分工是:

  • 一位项目参与者:在约定时间运行迁移脚本并打开一个 PR;
  • Owner:负责合并该 PR。

选择执行时机时要先检查在审的 PR,评估潜在冲突。如果仍有大型人工 PR 处于评审中,应等待它们合并后再执行迁移,否则迁移生成的全量 diff 会与这些 PR 产生大量冲突,增加所有人的返工成本。

执行迁移脚本的命令形如(脚本支持传入指定路径,也可不加参数默认遍历全部数据目录):

# 默认处理所有数据目录(dataFoldersMinusBrowsers) node scripts/migrations/007-experimental-false.js # 或只处理指定目录/文件 node scripts/migrations/007-experimental-false.js api css

由于脚本是幂等设计,重复运行不会产生多余 diff,这给"运行前检查、运行后复核"提供了安全余量。

五、Step 4:收尾

如果适用,迁移完成后再提交一个 PR,引入与该迁移相关的新 linter 检查或其他质量强制工具。这一步的意义在于把迁移的成果固化为长期约束——例如迁移把某类数据全部改写后,应让 linter 从此拒绝旧格式重新出现,防止数据回退。

最后,在最初的 issue 中宣布迁移完成,为整个流程画上句号。这也呼应了第一步"issue 作为全程讨论与跟踪场所"的设计。

六、从真实迁移脚本看数据改写手法

仓库中留存的迁移脚本提供了三种典型的数据改写手法,可作为后续编写迁移的参考模板:

6.1 语句级过滤:002-remove-webview-flags

对webview_android的支持语句数组做过滤,只保留不含flags的语句;若过滤后为空则置为version_added: false,只剩一条则简化为对象,多条则保留数组。这是一种典型的"删除某类语句"迁移。

6.2 跨浏览器派生数据:010-set-oculus-to-mirror与011-set-webview-ios-to-mirror

这两个脚本结构几乎相同,都是为缺失的浏览器键写入"mirror"字符串:

export const doSetOculusToMirror = (key, value) => { if (key === '__compat') { if (value.support.oculus === undefined) { value.support.oculus = 'mirror'; } } return value; };

"mirror"是 BCD 中特殊的支持语句值,表示该浏览器的数据自动镜像自其上游浏览器(如 Oculus 镜像 Chrome、WebView iOS 镜像 Safari),具体映射关系定义在各浏览器的browsers/<browser>.json中。这类迁移的价值在于:与其为每个特性手工补一份可能过期的版本号,不如统一用"mirror"声明派生关系,让构建期自动解析(镜像机制详见 schemas/compat-data-schema.md)。

6.3 文本格式规范化:012-descriptions-to-md

export const doDescriptionsToMarkdown = (key, value) => { if (key === '__compat') { if (value.description) { value.description = value.description.replace(/<\/?code>/g, '`'); } } return value; };

将description中残留的 HTML<code>/</code>标签替换为 Markdown 反引号,使描述字段与 schema 中"description 可用 Markdown 格式化"的约定保持一致。这类"文本层"迁移同样受益于 reviver 模式——不需要递归遍历,JSON.parse天然会访问到每个__compat节点。

七、迁移质量验证:测试、lint 与数据检查

迁移脚本合并前,建议结合仓库现有的验证体系进行完整检查(详见 docs/testing.md):

  • 单测:npm run unittest会运行包括scripts/migrations/*.test.js在内的全部测试;
  • 完整验证:npm test依次执行格式化检查(ESLint + Prettier + tsc)、数据 lint 与单元测试,其中 lint/lint.js 会加载所有数据目录并按 file / browser / feature / tree 四级作用域跑 linter;
  • 定向检索:npm run traverse -- [options] [folder]可在迁移前后检索特定浏览器、特定取值的数据分布,例如npm run traverse api,javascript -- -b webview_android -f mirror可确认 WebView 条目是否全部镜像化,用于验证迁移效果;
  • 统计观察:npm run stats [folder]可观察 exact / ranged 值占比的变化。

八、小结

BCD 的迁移流程本质上是一条"可审计的大规模数据变更流水线":issue 跟踪 → 自动化脚本 + 测试 → Owner 审批 → 择机执行 → linter 固化 → issue 宣布完成。对于数据规模达上万特性的仓库,这套流程把"修改全仓库数据"从高风险的人工操作,变成了可重复、可验证、可追溯的工程实践。如果后续你需要为 BCD 贡献类似的大规模改写,遵循 docs/migrations.md 的四步流程,并参考 scripts/migrations 中现存脚本的 reviver 模式与测试写法,即可快速上手。

  • 数据集
  • 开发工具

【免费下载链接】browser-compat-data

Browser compatibility data for Web technologies as displayed on MDN

项目地址:https://gitcode.com/gh_mirrors/br/browser-compat-data
点击查看免费下载

相关推荐

上一篇:draw.io 桌面版:三平台通用的免费画图工具,一条命令批量导出 6 种格式
下一篇:抖音批量下载工具 douyin-downloader 完整实战指南:从一条视频到千条素材只需 5 分钟

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询