关于core-js的分包设计

4,043 阅读3分钟

前言

关于 core-js 或许你还不清楚,但也一定在项目中直接或间接地使用过它。core-js 是一个 JavaScript 标准库,它包含了 ECMAScript 2020 在内的多项特性的 polyfills,以及 ECMAScriptproposals 阶段的特性、WHATWG/W3C 新特性等。因此它是一个现代化前端项目的“标准套件”。

说白了对于一些新的语法和API,老版本的浏览器无法全面兼容, core-js 就是提供新语法 api 的一个集合库。

设计理念

除了 core-js 本身的重要性,它的实现理念、设计方式都值得我们学习。

事实上,core-js 是一扇大门:

  • 通过 core-js,我们可以窥见前端工程化的方方面面;

  • core-js 又和 Babel 深度绑定,因此学习 core-js,也能帮助更好地理解 babel 生态,进而加深对前端生态的理解;

  • 通过对 core-js 的解析,我们正好可以梳理前端一个极具特色的概念——polyfill(垫片/补丁)。

core-js 工程一览 core-js 是一个由 Lerna 搭建的 Monorepo 风格的项目,在它的 packages 中,我们能看到五个相关包:

  • core-js

  • core-js-pure

  • core-js-compact

  • core-js-builder

  • core-js-bundle

我们先从 core-js 入手。core-js 实现的基础垫片能力,是整个 core-js 的逻辑核心。

比如我们可以按照如下代码引入全局 polyfills

import 'core-js';

或者按照:

import 'core-js/features/array/from'; 

的方式,按需在业务项目的入口引入某些 polyfills

core-js 为什么有这么多的 packages 呢?

实际上,它们各司其职,又紧密配合,接下来我们来具体分析。

core-js-pure 提供了不污染全局变量的垫片能力,比如我们可以按照:

 import _from from 'core-js-pure/features/array/from';
 import _flat from 'core-js-pure/features/array/flat'; 

的方式,来实现独立的导出命名空间,进而避免全局变量的污染。

core-js-compact 维护了按照 browserslist 规范的垫片需求数据,来帮助我们找到“符合目标环境”的 polyfills 需求集合,比如以下代码:

const {
    // array of required modules
    list, 
    // object with targets for each module
    targets, 
    } = require('core-js-compat')({
    targets: '> 2.5%'
});

就可以筛选出全球使用份额大于 2.5% 的浏览器范围,并提供在这个范围下需要支持的垫片能力。

core-js-builder 可以结合 core-js-compact 以及 core-js,并利用 webpack 能力,根据需求打包出 core-js 代码。比如:

require('core-js-builder')({
    targets: '> 0.5%',
    filename: './my-core-js-bundle.js',
})
.then(code => {})
.catch(error => {});

将会把符合需求的 core-js 垫片打包到 my-core-js-bundle.js 文件当中。

整个流程可以用代码演示为:

require('./packages/core-js-builder')(
    { 
        filename: './packages/core-js-bundle/index.js' 
    }
).then(done).catch(error => {
    // eslint-disable-next-line no-console
    console.error(error);
    process.exit(1);
});


babel-polyfill

值得一提的是,你可能听过 babel-polyfillbabel-polyfill 融合了 core-jsregenerator-runtime , 因此 babel-polyfill 本质就是 core-js

总结

总之,根据分包的设计,我们能发现 core-js 将自身能力充分解耦,提供出的多个包都可以被其他项目所依赖。比如:

core-js-compact 可以被 Babel 生态使用,由 Babel 分析出根据环境需要按需加载的垫片;

core-js-builder 可以被 Node.js 服务使用,构建出不同场景的垫片包。

参考

  1. babel结合core-js
  2. babel
  3. 《前端基建》