core-js-builder 实战指南:按目标环境定制 core-js 按需构建 Polyfill 包
2026/9/12 13:05:07 网站建设 项目流程

core-js-builder 实战指南:按目标环境定制 core-js 按需构建 Polyfill 包

【免费下载链接】core-jsStandard Library项目地址: https://gitcode.com/GitHub_Trending/co/core-js

本篇指南围绕 core-js-builder 展开,讲解如何通过编程式 API 从core-js中按需挑选模块、排除不需要的特性,并结合core-js-compat的兼容性数据与 browserslist 查询,为指定引擎版本构建定制化的 polyfill 产物。读完本文,你将掌握modulesexcludetargetssummaryformatfilename等全部选项的用法与底层执行原理,能够为项目生成体积最小、恰好满足目标环境需求的 polyfill 脚本。

一、为什么需要 core-js-builder

core-js作为标准库的 polyfill 集合,包含了 ES 标准提案、Web 标准等多达数百个独立模块(本仓库 packages/core-js/modules 下即有数百个.js模块文件)。直接全量引入会带来不必要的体积开销;而有些场景下,我们只希望为特定的目标引擎(例如老版本 IE、特定版本的 iOS Safari)补齐缺失的 API。

core-js-builder正是为这类场景设计的构建入口:它接收与core-js-compat同格式的modulesexcludetargets选项(详见 core-js-compat 说明),通过 webpack 将选中的模块打包成一个自包含的脚本文件,或者生成一组import/require语句。其能力可概括为:

  • 条件包含:只打包你需要的core-js特性模块;
  • 条件排除:黑名单机制剔除不需要的特性(例如体积敏感的es.math.*);
  • 按目标构建:传入 browserslist 查询或环境版本对象,自动只打包目标环境缺失的 polyfill。

二、快速上手:最小示例

core-js-builder提供的是异步 API,返回 Promise 字符串。在浏览器/现代构建流程中可以直接import,注意包类型为 CommonJS(见 package.json 中的"type": "commonjs")。

import builder from 'core-js-builder'; const bundle = await builder({ // 入口 / 模块 / 命名空间 / 上述的数组,默认情况下为全部 `core-js` 模块 modules: ['core-js/actual', /^esnext\.reflect\./], // 条目 / 模块 / 命名空间的黑名单,默认情况下为空列表 exclude: [/^es\.math\./, 'es.number.constructor'], // 可选的 browserslist 或 core-js-compat 格式查询 targets: '> 0.5%, not dead, ie 9-11', // 显示打包摘要,默认关闭 summary: { // 在控制台输出,可指定需要的部分或设为 `true` 全部开启 console: { size: true, modules: false }, // 在目标文件头部注释中输出,用法同 `summary.console` comment: { size: false, modules: true }, }, // 输出格式,默认为 'bundle',可为 'cjs' 或 'esm', // 此时结果不会被打包,而是包含所需模块的导入语句 format: 'bundle', // 可选的目标文件名,缺省时不会创建文件 filename: PATH_TO_MY_COREJS_BUNDLE, });

在 TypeScript 中使用时,需要将esModuleInterop设置为true

返回值与文件产出

  • filename省略时,函数不写任何文件,仅返回打包后的脚本字符串,方便你在内存中继续加工(如注入到自定义 loader);
  • 当提供filename时,会自动创建文件所在的目录(底层调用mkdirp)并写入结果,同时返回值仍包含完整脚本。

三、选项详解与源码级原理

1.modules:控制打包哪些模块

modules支持三种筛选形式,且可混用为数组(对应 compat.js 的getModules逻辑):

  • 入口点字符串:如'core-js/actual',会展开为该入口覆盖的全部模块(由core-js-compat/entries映射);
  • 模块名前缀字符串:如'esnext.reflect.',匹配所有以该前缀开头的模块名;
  • 正则表达式:如/^es\.math\./,对完整模块名做test匹配。

默认值为null,此时等价于打包core-js-compat中的全部模块(allModules)。注意:若某个过滤器匹配不到任何模块,会抛出TypeError: Specified invalid module name or pattern: ...,避免拼写错误被静默吞掉。

2.exclude:黑名单剔除

excludemodules使用同样的筛选语法(字符串前缀、入口、正则、数组)。在 compat.js 中,先归一化 exclude 集合,再从候选模块列表中过滤掉命中的项。典型用法是剔除体积大或业务不需要的模块:

exclude: [/^es\.math\./, 'es.number.constructor']

顺带一提,core-js-builder的 index.js 中还保留了一个已过时(计划在core-js@4移除)的blacklist参数作为exclude的别名,新代码请直接使用exclude

3.targets:按目标环境裁剪

targets可以是 browserslist 查询字符串,也可以是描述"各引擎最低支持版本"的对象。构建时会先通过core-js-compatcheckModule逐模块比对兼容性数据:若目标引擎版本低于模块所需版本,则该模块被判为"必需"而进入打包列表;若没有提供targets,则默认全部模块都需要(见 compat.js)。

对象形式的完整字段可参考 core-js-compat README,例如:

targets: { android: '4.0', // Android WebView 版本 bun: '0.1.2', // Bun 版本 chrome: '38', // Chrome 版本 'chrome-android': '18', // Android Chrome 版本 deno: '1.12', // Deno 版本 edge: '13', // Edge 版本 electron: '5.0', // Electron 版本 firefox: '15', // Firefox 版本 'firefox-android': '4', // Android Firefox 版本 hermes: '0.11', // Hermes 版本 ie: '8', // Internet Explorer 版本 ios: '13.0', // iOS Safari 版本 node: 'current', // Node.js 版本,'current' 表示当前运行的版本 opera: '12', // Opera 版本 'opera-android': '7', // Android Opera 版本 phantom: '1.9', // PhantomJS 版本 quest: '5.0', // Meta Quest 浏览器版本 'react-native': '0.70', // React Native 版本(默认 Hermes 引擎) rhino: '1.7.13', // Rhino 引擎版本 safari: '14.0', // Safari 版本 samsung: '14.0', // Samsung Internet 版本 esmodules: true | 'intersect', // true 时忽略 browsers 目标;'intersect' 时取 browsers 目标与 browserslist 目标的交集,并取较大版本 browsers: '> 0.25%', // Browserslist 查询或目标浏览器对象 }

在 targets-parser.js 中可以看到底层处理细节:browsers字段会交给browserslist()解析为引擎版本列表;esmodules: true会引入支持 ES Modules 的最低版本集合(数据来自external);node: 'current'会被替换为process.versions.node。同时,browserslist 别名(如ios_safand_chrie_mob)会被统一映射到内部引擎名,非法引擎名会被过滤,同一引擎的多个版本取最小值。

4.format:三种输出形态

format决定产物的组织形式,可选值为'bundle'(默认)、'cjs''esm',非法值会直接抛出TypeError('Incorrect output type')

  • bundle:通过 webpack 将所需模块打包为单个 IIFE 脚本,自包含、可直接用<script>引入。打包时(index.js)会以mode: 'none'hashFunction: 'md5'配置 webpack,入口为core-js/modules/<name>解析路径,产物生成在临时目录并读回后删除临时文件,同时对__webpack_require__做压缩处理;
  • cjs:不打包,输出一串require('core-js/modules/<name>');语句,适合在 Node.js / CommonJS 环境中直接 import 使用;
  • esm:不打包,输出一串import 'core-js/modules/<name>.js';语句,适合接入现代打包器进一步 tree-shaking。

后两种格式只是模块引用列表,体积极小,且不包含执行逻辑——真正的 polyfill 代码仍由core-js本体提供。

5.summary:打包摘要报告

summary分为consolecomment两个通道,每个通道可设为布尔值或{ size, modules }对象:

  • 设为truesizemodules全部开启;
  • 设为对象:仅开启指定项;
  • 默认关闭({})。

console 通道会在控制台输出彩色摘要:size打印产物体积(KB),modules逐行列出每个模块名,若提供了targets还会附带该模块对应的引擎版本 JSON(见 index.js)。

comment 通道则把信息写进输出文件头部的注释块:size追加size: x.xxKB w/o commentsmodules追加逐行模块清单。方便日后排查"这个 bundle 里到底装了哪些 polyfill"。

6.filename:写出产物文件

可选。提供时自动mkdirp创建父目录并写入最终脚本(含 banner 注释);缺省时仅返回字符串。banner 由 config.js 生成,包含core-js版本号、版权声明、许可证与源码链接,例如:

/** * core-js 3.50.0 * © 2013–2025 Denis Pushkarev (zloirock.ru), 2025–2026 CoreJS Company (core-js.io). All rights reserved. * license: ... * source: https://github.com/zloirock/core-js */

四、完整的实战组合示例

以下示例展示如何为"需要支持现代浏览器 ES Modules、同时兼容 IE 9-11"的场景构建一个定制 bundle,并输出体积与模块清单报告:

import builder from 'core-js-builder'; import { writeFileSync } from 'node:fs'; const code = await builder({ modules: ['core-js/actual', /^web\./, 'esnext.observable'], exclude: [/^es\.math\./, /^es\.reflect\./, 'es.array.flat'], targets: { browsers: '> 0.5%, not dead', ie: '9', }, format: 'bundle', summary: { console: { size: true, modules: true }, comment: { size: true, modules: false }, }, filename: './dist/my-corejs-bundle.js', }); // 返回值同样可用,例如再手动追加一段自定义代码 writeFileSync('./dist/my-corejs-bundle.custom.js', code + '\n// custom tail\n');

运行后控制台会输出类似:

bundling `./dist/my-corejs-bundle.js`, size: 87.42KB bundling `./dist/my-corejs-bundle.js`, modules: es.array.push for {"ie":"9"} es.string.trim for {"ie":"9"} ...

若某个模块在目标环境下并不缺失,它不会出现在列表中;若所有目标环境都不缺任何模块(例如只针对最新 Node),summary.console.modules会打印nothing,此时产物可能只包含 banner。

五、构建流程的内部原理

一次builder()调用的完整执行链路如下(对应 index.js 与 compat.js):

  1. 参数校验与归一化:校验format合法性,将summary两个通道统一为{ size, modules }布尔对象;
  2. 模块筛选:调用core-js-compatcompat({ targets, modules, exclude }),内部依次完成 exclude 归一化、模块列表交集计算、proposal 稳定化过滤(filterOutStabilizedProposals)、按 targets 逐模块判定必需性,最终返回{ list, targets }
  3. 按 format 生成代码
    • bundle:webpack 以选中模块为多入口打包 → 读取临时产物 → 包裹为!function (undefined) { 'use strict'; ... }();IIFE;
    • cjs/esm:分别生成require(...)/import '...'语句序列;
  4. 附加 banner 与摘要:将 banner 置于最前,按summary.comment追加注释,按summary.console打印报告;
  5. 可选写文件filename存在时创建目录并写入,最后返回完整脚本字符串。

这一流程在 tests/builder/builder.mjs 中有直接验证:测试用modules: 'core-js/actual'exclude: [/group-by/, 'esnext.typed-array.to-spliced']targets: { node: 16 }format: 'esm'构建,并断言结果中包含es.error.causees.array.pushesnext.array.groupweb.structured-clone等模块的 import 语句,同时不包含es.weak-setesnext.weak-set.from、被排除的esnext.array.group-by等。这个测试清晰地演示了"入口展开 + 黑名单排除 + 按目标裁剪"三者协同的预期行为。

六、使用注意事项

  • TypeScript:启用esModuleInterop才能直接import builder from 'core-js-builder';包自带类型声明 index.d.ts,其中完整定义了FormatSummaryEntrySummary等类型;
  • Node.js 版本:包声明engines.node >= 8.9.0,代码中刻意避开了fs.promisesmkdirrecursive选项,以兼容旧版 Node(源码中留有TODO: replace ... after dropping NodeJS < 10 support注释);
  • 运行时依赖:构建过程依赖core-jscore-js-compat(两者均锁定为同版本3.50.0)、webpack>=4.47.0 <5)与mkdirp,这些是打包期依赖,产物本身是自包含脚本,无需运行时携带;
  • 正则过滤的命名空间约定es.esnext.web.stage.等前缀分别对应标准已定稿特性、提案特性、Web 标准与 Stage 提案模块,可据此写出精确的包含/排除模式(可对照 packages/core-js/modules 与 packages/core-js/proposals 下的实际模块命名确认);
  • targets缺省意味着打包全部所选模块,此时体积最大,务必在发布到生产环境前明确指定目标环境。

七、与其他包的分工

core-js-builder处于本仓库工具链的"构建出口"位置:core-js提供全部 polyfill 模块实现,core-js-compat提供"某个模块在某个引擎版本下是否需要"的兼容性数据与查询 API,而core-js-builder将两者组合,按需产出最终脚本。若你只需要"查询某环境下需要哪些模块"而不需要打包,可直接使用core-js-compatcompat({ targets, modules, version, inverse })获得模块清单与逐模块目标版本映射(完整 API 见 core-js-compat 说明),这也正是builder内部第 2 步所调用的能力。

【免费下载链接】core-jsStandard Library项目地址: https://gitcode.com/GitHub_Trending/co/core-js

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

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

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

立即咨询