共计 5029 个字符,预计需要花费 13 分钟才能阅读完成。
公众号
前言
或者你可能不晓得 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,底层的机制都是由 internals
和modules
外部的 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 及垫片理念(这篇文章为拉钩付费文章,无奈分享链接)