十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

core-js-compat 兼容性数据引擎:基于 Browserslist 精准计算 core-js polyfill 模块清单

core-js-compat 兼容性数据引擎:基于 Browserslist 精准计算 core-js polyfill 模块清单 core-js-compat 兼容性数据引擎基于 Browserslist 精准计算 core-js polyfill 模块清单【免费下载链接】core-jsStandard Library项目地址: https://gitcode.com/GitHub_Trending/co/core-jscore-js-compat是 core-js 生态中专司“兼容性情报”的包它内置了每个 core-js 模块如es.array.at、esnext.iterator.map在各个运行时引擎中可用/缺失的版本数据并对外提供compat()这一核心查询 API输入一段 Browserslist 查询或目标环境对象即可精确输出“需要打补丁的模块清单”与“每个模块具体缺在哪个引擎版本”。在 core-js 项目中它是core-js-builder按目标环境裁剪构建产物的数据源对于任何想实现按需 polyfill、减少打包体积的工程化项目掌握它就能把“兼容性策略”从拍脑袋变成可编程、可验证的工程决策。读完本文你将掌握compat()全部选项的语义、targets的两种写法、模块过滤与版本回溯的机制并理解这份数据是如何从源码生成和校验的。一、core-js-compat 是什么包的定位与核心数据流从仓库目录 packages/core-js-compat/package.json 可以看到当前仓库中该包的版本为3.50.0类型为 CommonJStype: commonjs入口是 index.js并附带了完整的 TypeScript 声明types: index.d.ts。它唯一的运行时依赖是browserslist^4.28.8Node 版本要求 6.4.0。包的职责可以用一句话概括维护“core-js 模块 × 运行时引擎版本”的兼容性矩阵并把“目标环境”翻译成“需要的模块列表”。整个数据流如下原始数据保存在 packages/core-js-compat/src/data.mjs形如{ es.array.at: { chrome: 92, firefox: 90, safari: 15.4, ... } }表示“该模块在各引擎中最早可用的版本”构建脚本 scripts/build-compat/data.mjs 通过 src/mapping.mjs 中的引擎映射表Chrome→Node、Chrome→Deno、Chrome→Electron、Safari→iOS 等把稀疏数据补全为完整矩阵产出data.json、modules.json、external.json等构建产物运行时入口 compat.js 读取这些数据结合 targets-parser.js 解析出的目标环境逐模块比对版本输出{ list, targets }。二、核心 APIcompat()一步求出所需模块清单官方 README 给出的最典型用法如下这也是core-js-builder内部实际调用的方式import compat from core-js-compat; const { list, // array of required modules targets, // object with targets for each module } compat({ targets: 1%, // browserslist query or object of minimum environment versions to support modules: [ // optional list / filter of modules - regex, string or an array of them: core-js/actual, // - an entry point esnext.array.unique-by, // - a module name (or just a start of a module name) /^web\./, // - regex that a module name must satisfy ], exclude: [ // optional list / filter of modules to exclude, the signature is similar to modules web.atob, ], version: 3.50, // used core-js version, by default - the latest inverse: false, // inverse of the result - shows modules that are NOT required for the target environment });list是按顺序排列的模块名数组可直接作为 polyfill 引入清单使用targets则以模块名为键给出该模块在哪些引擎的哪些版本上确实缺失即需要打补丁的具体环境。例如上述配置在文档中给出的输出形态为console.log(targets); /* { es.error.cause: { ios: 14.5-14.8 }, es.array.includes: { firefox: 100 }, es.array.push: { chrome: 100, edge: 101, ios: 14.5-14.8, safari: 15.4 }, esnext.array.group: { chrome: 100, edge: 101, firefox: 100, ios: 14.5-14.8, safari: 15.4 }, web.immediate: { chrome: 100, edge: 101, firefox: 100, ios: 14.5-14.8, safari: 15.4 }, web.structured-clone: { chrome: 100, edge: 101, firefox: 100, ios: 14.5-14.8, safari: 15.4 } // ... } */注意一个细节targets中的版本是目标环境的版本而不是该模块“缺失”的边界版本。比如es.array.at: { ios: 14.5-14.8 }表示“在您声明的目标集合里iOS Safari 14.5-14.8 还不支持Array.prototype.at因此需要引入es.array.at这个模块”。判定逻辑在 compat.js 的checkModule中实现function checkModule(name, targets) { const result { required: !targets, targets: {} }; if (!targets) return result; const requirements data[name]; // 该模块在各引擎的“最低可用版本” for (const [engine, version] of targets) { if (!has(requirements, engine) || compare(version, , requirements[engine])) { result.required true; result.targets[engine] version; } } return result; }即目标引擎版本低于该模块的最低可用版本或数据中根本没有该引擎的记录则该模块对当前环境是必需的。版本比较使用 helpers.js 中自实现的三段式 SemVer 比较major.minor.patch逐段比较缺省段按0处理不依赖额外的 semver 库。结果集合的组装顺序在 compat.js 的主流程中最终结果的组装顺序是modules或已废弃的filter先经normalizeModules归一化为 Setexclude同样归一化后把被排除的模块从modules中剔除若指定了version用getModulesListForTargetVersion(version)求交集保证结果只包含该 core-js 版本实际存在的模块默认非inverse情况下调用filterOutStabilizedProposals把“已转正的提案模块”过滤掉见下文逐模块执行checkModule满足条件check.required ^ inverse为真时加入list与targets。modules/exclude若传了非法值如空字符串导致匹配不到任何模块会抛出Specified invalid module name or pattern的TypeError见 compat.js。三、targets选项详解Browserslist 查询与目标对象targets支持两种形态一段 Browserslist 查询字符串或一个声明“各引擎最低支持版本”的对象。3.1 Browserslist 查询直接传入字符串即可defaults, not IE 11, maintained node versions它会被交给 targets-parser.js 内部的browserslist(query)展开为[引擎, 版本]对列表。browsers字段也接受同样的查询形式见下文 3.3。3.2 目标对象完整字段表对象形式声明各引擎的最低版本以下字段全部可选示例与注释来自官方 README版本值均为字符串({ android: 4.0, // Android WebView version bun: 0.1.2, // Bun version chrome: 38, // Chrome version chrome-android: 18, // Chrome for Android version deno: 1.12, // Deno version edge: 13, // Edge version electron: 5.0, // Electron framework version firefox: 15, // Firefox version firefox-android: 4, // Firefox for Android version hermes: 0.11, // Hermes version ie: 8, // Internet Explorer version ios: 13.0, // iOS Safari version node: current, // NodeJS version, current 当前运行的 Node 版本 opera: 12, // Opera version opera-android: 7, // Opera for Android version phantom: 1.9, // PhantomJS headless browser version quest: 5.0, // Meta Quest Browser version react-native: 0.70, // React Native version (默认 Hermes 引擎) rhino: 1.7.13, // Rhino engine version safari: 14.0, // Safari version samsung: 14.0, // Samsung Internet version esmodules: true | intersect, // 见 3.3 browsers: 0.25%, // Browserslist query 或含目标浏览器的对象 })类型定义见 compat.d.ts这些引擎名来自 shared.d.ts 中声明的Target联合类型且支持别名quest/oculus、react-native/react/reactnative、opera-android/opera_mobileopera_mobile已标记为 deprecated。3.3esmodules与browsers两个特殊字段browsers值可以是一段 Browserslist 查询字符串或数组也可以是{ engine: version }形式的目标对象二者都会被展开并合并进最终的引擎集合见 targets-parser.js。esmodules: true忽略browsers目标直接使用“支持 ES Modules 的所有浏览器”的最低版本集合。该集合来自 src/external.mjsexport default { modules: { bun: 0.1.1, chrome: 61, deno: 1.0, edge: 16, firefox: 60, node: 13.2, safari: 10.1, }, };从这份数据可见ES Modules 基线定义为 Chrome 61、Edge 16、Firefox 60、Safari 10.1、Node 13.2 等见 targets-parser.js。esmodules: intersect将browsers目标与browserslist目标取交集每个引擎取两者中更高的版本因为版本越高越严格取最大值等价于“同时满足两套要求”。实现见 targets-parser.js若某引擎不在 ES Modules 基线数据中则从结果中删除。3.4 解析细节别名、合法性过滤与去重targets-parser.js还做了几件容易被忽略的事targets-parser.js引擎别名归一化and_chr→chrome-android、and_ff→firefox-android、ie_mob→ie、ios_saf→ios、oculus→quest、op_mob/opera_mobile→opera-android、react/reactnative→react-native目标键统一转为小写toLowerKeys只保留validTargets白名单targets-parser.js中的引擎未知引擎被静默过滤同一引擎出现多个版本时reduced取最低版本compare(version, , reduced.get(engine))时更新因为目标是“最低支持的版本”node: current会被替换为process.versions.node的实际版本号。四、模块过滤modules与excludemodules与exclude使用完全相同的过滤器语法见 compat.js支持三种形式可混合传入数组形式示例语义入口点entry pointcore-js/actual展开为该入口点下挂载的全部模块依据entries映射模块名前缀esnext.array.unique-by精确匹配该模块名若传的是前缀如esnext.array.匹配所有以该前缀开头的模块正则/^web\./模块名需满足该正则具体匹配逻辑字符串先查entries映射表存在则直接返回对应模块数组否则退化为allModules.filter(it it.startsWith(filter))正则则直接对全部模块名执行test。无论哪种方式匹配结果为空都会抛TypeError。最终经normalizeModules合并为一个Set去重。exclude的典型用途是排除某些已知有坑或有替代方案的模块例如 README 示例中排除了web.atob它会在modules归一化之后被剔除。filter参数是modules的旧名已在类型声明中标记deprecated见 compat.d.ts并计划在 core-js4 移除见 compat.js 的 TODO 注释。已转正提案的自动折叠默认情况下compat()会执行filterOutStabilizedProposalshelpers.js若同时存在esnext.xxx与已转正的es.xxx两个模块则删除esnext.xxx。这与 core-js 的版本演进策略一致——提案一旦进入标准esnext.命名空间的模块会被es.版本取代避免同一功能重复打补丁。在 src/data.mjs 中可以看到大量renamed映射如esnext.array.at→es.array.at正是这套演进机制的数据侧印证。五、version与inverse版本约束与反向查询5.1version限定 core-js 版本范围不同 core-js 版本能提供的模块集合不同version用于把结果限制在指定版本的可用模块内默认是最新版本。其实现是 get-modules-list-for-target-version.jsmodule.exports function (raw) { const corejs semver(raw); if (corejs.major ! 3) { throw new RangeError(This version of core-js-compat works only with core-js3.); } const result []; for (const version of Object.keys(modulesByVersions)) { if (compare(version, , corejs)) { result.push(...modulesByVersions[version]); } } return intersection(result, modules); };modulesByVersions数据源在 src/modules-by-versions.mjs记录了“从 3.1 开始每个 minor 版本新增了哪些模块”因此该函数返回“目标版本及之前累积引入的所有模块”再与全部模块求交集保证顺序与合法性。注意它只支持 core-js3传入其他主版本会抛RangeError。在 compat.js 中这个结果再与已过滤的modules取交集完成版本约束。5.2inverse反向模式inverse: true时输出逻辑取反compat.js 的check.required ^ inverse返回目标环境中“不需要”的模块列表。这在做兼容性审计或对比不同目标策略时很有用——例如想确认“哪些新 API 我可以放心在目标环境直接用而无需 polyfill”。注意反向模式下filterOutStabilizedProposals 不再执行以保证结果完整。六、附加 APIdata/entries/modules/getModulesListForTargetVersioncore-js-compat默认导出的其实是compat()函数与以下四个属性的合并对象见 index.js也可以按子路径单独引入// 等价于上面的 compat({ targets, modules, version }) require(core-js-compat/compat)({ targets, modules, version }); // { list, targets } // 或 require(core-js-compat).compat({ targets, modules, version }); // 完整兼容性数据{ [模块名]: { [引擎名]: 最早支持版本 } } require(core-js-compat/data); // 或 require(core-js-compat).data; // 入口点 → 模块数组 的映射{ [入口点]: Array模块名 } require(core-js-compat/entries); // 或 require(core-js-compat).entries; // 全部模块名数组 require(core-js-compat/modules); // 或 require(core-js-compat).modules; // 指定 core-js 版本可用的模块子集 require(core-js-compat/get-modules-list-for-target-version)(3.50); // Array模块名 // 或 require(core-js-compat).getModulesListForTargetVersion(3.50);其中data是判断“某模块在某引擎是否缺失”的直接依据结构为{ [ModuleName]: { [EngineName]: EngineVersion } }值为该引擎中该模块的最低可用版本。TypeScript 侧对应声明见 index.d.ts 与 get-modules-list-for-target-version.d.ts。entries映射则由 scripts/build-compat/entries.mjs 通过静态解析packages/core-js下各入口文件actual/、es/、full/、stable/、web/、proposals/、stage/等的 import 依赖链自动生成因此入口点展开结果与实际打包行为完全一致。七、数据是如何生成的从稀疏源数据到完整矩阵7.1 源数据与手工标注的“坑”src/data.mjs约 3300 行是手工维护的稀疏兼容性数据只标注部分引擎并大量注释了各引擎的真实 Bug 场景。例如es.symbol.disposeNode 标注为20.5.0注释说明 Node 20.4.0 虽引入该 API 但 descriptor 实现有误src/data.mjses.array.includesFirefox 标注102而非最初支持的 48注释指出 FF99-101 在稀疏数组上存在缺陷src/data.mjses.suppressed-error.constructorChrome 标注 136注释记录了 Chromium 多次启用/回滚的历史src/data.mjs。这解释了为什么兼容性数据不能用“第一次实现版本”一刀切——core-js 的兼容性判定标准是“行为是否与规范完全一致”而非“API 是否存在”。7.2 引擎映射与自动补全src/mapping.mjs 维护了跨引擎版本映射ChromeToNode含 io.js 历史版本、ChromeToDeno、ChromeToElectron、ChromeToOpera分段公式、ChromeToChromeAndroid、ChromeAndroidToSamsung、SafariToIOS、SafariToBun、HermesToReactNative等每个表都标注了数据来源如 Node 发行记录、Electron releases、MDN browser-compat-data。构建脚本 scripts/build-compat/data.mjs 会基于这些映射把稀疏数据补全为完整矩阵例如es.*模块通过ChromeToNode/ChromeToDeno推断 Node/Deno 版本通过ChromeToElectron推断 Electron 版本再通过SafariToIOS等补齐移动端最后对键排序输出 JSON 构建产物data.json、modules.json、external.json并同步生成浏览器端测试数据 tests/compat/compat-data.js 的基线。7.3 数据的正确性校验仓库提供了两层自动化保障tests/compat-data/tests-coverage.mjs 校验“每个 compat 数据模块都有对应的运行时测试”它把数据中的全部模块与 tests/compat/tests.js 里注册的测试做比对缺失测试或新增了数据外的测试都会直接报错确保数据不落后于测试、测试不落后于数据tests/compat-data/modules-by-versions.mjs 校验modules-by-versions与线上core-js-compat3.0.0基线一致防止新增模块漏登记版本。八、在 core-js 生态中的真实应用core-js-builder 的按需构建compat()最直接的消费者是core-js-builder。在 packages/core-js-builder/index.js 中const { list, targets: compatTargets } compat({ targets, modules, exclude: blacklist || exclude });构建器把compat()返回的list作为 webpack 的入口模块数组list.map(it require.resolve(core-js/modules/${ it }))见 index.js从而只为目标环境打包缺失的 polyfilltargets则用于在summary输出中打印每个模块对应的缺失环境index.js。从 core-js-builder/index.d.ts 可以看到builder 的modules、exclude、targets选项类型直接复用了core-js-compat的CompatOptions。这就是“按需 polyfill、压缩体积”的核心链路环境声明 → compat 数据 → 精确模块清单 → 最小化打包。九、写在最后如何为这份数据做贡献如果你在真实环境发现某个引擎版本的兼容性标注不准确可以参与维护这份数据。仓库的 CONTRIBUTING.md 中“如何更新 core-js-compat 数据”一节说明了流程通常需要先在 tests/compat/tests.js 中补充/修正对应模块的运行时测试再更新 src/data.mjs 中的版本标注然后重新运行构建脚本 scripts/build-compat/data.mjs 生成产物并确保通过 tests/compat-data 下的覆盖率校验。仓库还提供了可视化兼容性表格与浏览器测试运行器可直接在浏览器中逐模块查看各引擎的支持情况其数据来源即 tests/compat/tests.js 的运行时探测结果。从“目标环境”到“精确 polyfill 清单”core-js-compat用一份可维护、可测试、可版本回溯的数据把前端工程化里最容易被拍脑袋决定的兼容性策略变成了一套严谨可复用的基础设施。【免费下载链接】core-jsStandard Library项目地址: https://gitcode.com/GitHub_Trending/co/core-js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表