乐趣区

关于javascript:手把手教你如何配置Babel2揭开corejs的面纱

公众号

前言

或者你可能不晓得 core-js 仓库,不过肯定在我的项目中间接或间接地应用过它

core-js 仓库 是一个 JavaScript 规范库,它蕴含了 ECMAScript 2021 在内的多项个性的 polyfill,以及 ECMAScript 在 proposals 阶段的个性、WHATWG/W3C 新个性等。

core-js 仓库和 Babel 有一些关联,把握了 core-js,能帮忙你更好地了解 babel 生态。同时,通过对 core-js 的解析,能够更好的深刻理解 polyfill(垫片 / 补丁)

core-js 仓库 目前最新的版本是 core-js@3.x.x

官网不举荐持续应用 core-js@2.x.x,core-js@3.x.x 有更丰盛的 polyfill,和 Babel 联合会有更好的将来。上面介绍的内容都是指的 core-js@3 的版本。

指标

带着一下问题去找答案

  • core-js 仓库是什么?
  • core-js 仓库外面三个不同版本的区别是什么?

core-js 仓库

core-js 是一个由 Lerna 搭建的 Monorepo 格调的我的项目,在它的 packages 文件夹中有五个包:

  • package/core-js
  • package/core-js-pure
  • package/core-js-bundle
  • package/core-js-compact : 保护了依照 browserslist 标准的垫片需要数据,来帮忙咱们找到“合乎指标环境”的 polyfills 需要汇合
  • package/core-js-builder : 能够联合 core-js-compact 以及 core-js,并利用 webpack 能力,依据需要打包出 core-js 代码
    上面具体介绍一下 core-js,core-js-pure,core-js-bundle 区别。上面是官网文档中的例子:
// global version
npm install --save core-js@3.13.0
// version without global namespace pollution
npm install --save core-js-pure@3.13.0
// bundled global version
npm install --save core-js-bundle@3.13.0

global version

翻译:全局版本。package/core-js中 polyfill 的代码会间接批改全局变量,净化全局变量。咱们看一个 Promise 的例子:

import 'core-js/features/promise'
Promise.resolve(32).then(x => console.log(x));

core-js/features/promise是对浏览器的全局 window 对象进行了从新赋值,重写了 window 的 Promise 及其原型链。

全局版本有两种应用形式:

第一种形式:只在我的项目入口文件中,手动引入core-js。例如:

import 'core-js'; // <- at the top of your entry point

Array.from(new Set([1, 2, 3, 2, 1]));          // => [1, 2, 3]
[1, [2, 3], [4, [5]]].flat(2);                 // => [1, 2, 3, 4, 5]
Promise.resolve(32).then(x => console.log(x)); // => 32

第二种形式在入口文件手动按需引入须要的 polyfill

import 'core-js/features/array/from'; // <- at the top of your entry point
import 'core-js/features/array/flat'; // <- at the top of your entry point
import 'core-js/features/set';        // <- at the top of your entry point
import 'core-js/features/promise';    // <- at the top of your entry point

Array.from(new Set([1, 2, 3, 2, 1]));          // => [1, 2, 3]
[1, [2, 3], [4, [5]]].flat(2);                 // => [1, 2, 3, 4, 5]
Promise.resolve(32).then(x => console.log(x)); // => 32

version without global namespace pollution

翻译:不净化全局变量的版本。package/core-js-pure 提供了不净化全局变量的垫片能力,然而在应用的时候,不能一次性引入所有的 polyfill,必须依据每个文件的须要,独自引入须要的 modules。例如:

import from from 'core-js-pure/features/array/from';
import flat from 'core-js-pure/features/array/flat';
import Set from 'core-js-pure/features/set';
import Promise from 'core-js-pure/features/promise';

// 留神这里必须是 form()这种形式调用,而不是[].from 形式。这是和 package/core-js 的区别
from(new Set([1, 2, 3, 2, 1]));                // => [1, 2, 3]
flat([1, [2, 3], [4, [5]]], 2);                // => [1, 2, 3, 4, 5]
Promise.resolve(32).then(x => console.log(x)); // => 32

相似 Array.from,Array.prototype 这种在内置对象或内置类上扩大出的新的实例办法或静态方法,都不能依照实例办法或静态方法间接调用,必须像 from(new Set([1, 2, 3, 2, 1])); 这种形式应用。

bundled global version

翻译:打包好的 全局版本 package/core-js-bundle 是曾经编译打包好的版本,蕴含全副的 polyfill,能够在浏览器外面通过 script 形式间接加载。

CommonJS API

官网文档有一个上面的例子。列举了很多应用 polyfill 的形式。

// polyfill all `core-js` features:
import "core-js";
// polyfill only stable `core-js` features - ES and web standards:
import "core-js/stable";
// polyfill only stable ES features:
import "core-js/es";

// if you want to polyfill `Set`:
// all `Set`-related features, with ES proposals:
import "core-js/features/set";
// stable required for `Set` ES features and features from web standards
// (DOM collections iterator in this case):
import "core-js/stable/set";
// only stable ES features required for `Set`:
import "core-js/es/set";
// the same without global namespace pollution:
import Set from "core-js-pure/features/set";
import Set from "core-js-pure/stable/set";
import Set from "core-js-pure/es/set";

// if you want to polyfill just required methods:
import "core-js/features/set/intersection";
import "core-js/stable/queue-microtask";
import "core-js/es/array/from";

// polyfill reflect metadata proposal:
import "core-js/proposals/reflect-metadata";
// polyfill all stage 2+ proposals:
import "core-js/stage/2";

第一次看下面代码,一脸懵逼,core-js/es,core-js/web,core-js/proposals,core-js/stable,core-js/features,core-js/stage这些都是啥玩意? 为什么还有等价关系?。

于是看了一下 core-js 仓库 文件夹构造,如下:

因为文件目录太长,这里只列出 1 级目录构造

tree -L 1
# 输入后果
├── LICENSE
├── README.md
├── configurator.js
├── es
├── features
├── index.js
├── internals
├── modules
├── package.json
├── postinstall.js
├── proposals
├── stable
├── stage
└── web

core-js 仓库的源码构造,展现了命名空间对应的文件夹。并且每个 namespace 上面都有一个index.js

  • core-js/index.js 等同于 import 'core-js'
  • core-js/es 等同于 core-js/es
    …..
    ….

咱们看一下 core-js/index.js的源码

module.exports = require('./features');

./features文件夹上面的index.js

//require('../modules/es.*
require('../modules/es.symbol');
require('../modules/es.symbol.description');
....
....
//require('../modules/esnext.*');
require('../modules/esnext.aggregate-error');
require('../modules/esnext.array.at');
....
....
//require('../modules/web.*');
require('../modules/web.dom-collections.for-each');
require('../modules/web.dom-collections.iterator');
....
....

module.exports = require('../internals/path');

通过查看源码,得悉了 import "core-js"等价于

import "core-js/es";
import "core-js/web";
import "core-js/proposals";

其它的等价关系,都能够从源码里看的一清二楚。

package/core-js的 polyfill,底层的机制都是由 internalsmodules外部的 module 来实现的。官网不举荐间接我的项目中间接应用这两个文件夹的 module,因为它们是外部实现,很可能在版本迭代中发生变化

package/core-js-pure的源码与 package/core-js 仅仅只有 internals 和 modules 两个文件夹有区别,其它的都是一样的。关上下面的源码库看到 core-js-pure 外面只有一个 overrides 文件夹,蕴含了 internals 和 modules 两个文件夹。很容易就能猜到,core-js-pure 这个包是在复制了 core-js 的包根底上,而后笼罩了 internals 和 modules 之后失去的。

与 Babel 配合应用

官网文档中列举了

  • @babel/polyfill
  • @babel/preset-env
  • @babel/runtime

这里先不介绍一下,前面两个章节《如何 Babel 的配置文件,设计一个“最完满”的 Polyfill 计划》分享中具体形容。

参考文献

  • core-js 官网
  • core-js 及垫片理念(这篇文章为拉钩付费文章,无奈分享链接)
退出移动版