致我们学前端的小时光—corejs与env、runtime的不解之缘

栏目: JavaScript · 发布时间: 6年前

内容简介:最近在看致我们暖暖的小时光,有点不可自拔。文章具有翻译向,具体的可以看文末的链接。随着ES6的正式发布,以及ES2016、ES2017...每年的稳定更新,还有新提案的不断出现,使得JavaScript越来越成熟。但是对于一些新的语法和API,老版本的浏览器无法全面兼容。babel的出现,解决了在老版本浏览器使用新语法的问题,它现在不仅仅是一个ES6 to ES5单纯的语法转换工具,更是一个规范和生态,帮我们去更高效的处理JavaScript。

前言

最近在看致我们暖暖的小时光,有点不可自拔。

文章具有翻译向,具体的可以看文末的链接。

随着ES6的正式发布,以及ES2016、ES2017...每年的稳定更新,还有新提案的不断出现,使得JavaScript越来越成熟。但是对于一些新的语法和API,老版本的浏览器无法全面兼容。babel的出现,解决了在老版本浏览器使用新语法的问题,它现在不仅仅是一个ES6 to ES5单纯的语法转换工具,更是一个规范和生态,帮我们去更高效的处理JavaScript。

@babel/preset-env登场

@babel/preset-env是作为babel-preset-es2015的替代品出现的,主要的作用是用来转换那些已经被正式纳入TC39中的语法。所以它无法对那些还在提案中的语法进行处理,对于处在stage中的语法,需要安装对应的plugin进行处理。

除了语法转换,@babel/preset-env另一个重要的功能是对polyfill的处理。新加入标准库的,可能是一些语法特性,比如箭头函数等,还有可能是一些新的API,比如promise、set、inclues等。

对于语法,babel可以通过生成静态语法树,去做一些转换,生成对应的ES5的代码。

但是对于新的API,需要浏览器去原生支持,或者使用大量的代码去进行API的模拟。@babel/polyfill就是API的垫片,通过引入这些垫片,使得低版本的浏览器能模拟实现那些新的API。

而今天的主角core-js就是@babel/polyfill的核心依赖,它现在已经发布了3.0的版本,而且@babel/preset-env在7.4.0的版本已经支持这个最新的版本。大版本的升级,会带来一些破坏性,但是相应的也会带来很多优势。

core-js 被遗忘的包

core-js是什么

  • 它是JavaScript标准库的polyfill
  • 它尽可能的进行模块化,让你能选择你需要的功能
  • 它可以不污染全局空间
  • 它和babel高度集成,可以对core-js的引入进行最大程度的优化

core-js升级的动机

  • core-js中的破坏性变更只能在主版本的升级中进行
  • core-js@2.0的版本已经在一年半之前冻结,所有的新特性只会添加到3.0的分支中

core-js@3的重要改变

  • 对于ECMAScript中已经稳定的功能,core-js已经几乎完全支持,并在core-js@3中引入了一些新的功能
  • 对于一些已经加入到ES2016-ES2019中的提案,现在已经被标记为稳定功能
  • 增加了proposals配置项,对处在提案阶段的api提供支持,但是因为提案阶段并不稳定,在正式加入标准之前,可能会有大的改动,需要谨慎使用;对于一些改变巨大的提案,也进行了对应的更新
  • 增加了对一些web标准的支持,比如URL 和 URLSearchParams
  • 删除了一些过时的特性

monorepos 包的拆分

core-js@2一个最常见的问题就是包的体积太大(~2M),并且有很多重复的文件被引用。基于这个原因,core-js@3对包进行拆分,三个核心的包分别是

  • core-js:定义全局的polyfill(~500k, 40k minified and gzipped)
  • core-js-pure:提供不污染全局环境的polyfill,等价于core-js@2/library(~440k)
  • core-js-compat :包含了core-js模块和API必要的数据,通过browserslist来生成所需要的core-js模块的列表

在以前的版本中,已进入ECMAScript标准的特性用 es6. 的前缀来表示,提案阶段的特性用 es7. 的前缀来表示,选择这个前缀的原因是在2014年的时候ES6以后的所有特性都考虑使用ES7来进行命名。

在cores-js@3的版本中,所以规范中的特性都使用 es. 这个前缀,而提案中的特性使用 esnext. 这个前缀。

几乎所有的CommonJS的入口文件都已经发生改变。在core-js@3中,包含了更多的模块入口。这使得对于目标浏览器的按需支持更加的具有灵活性,同时可以带来文件大小方面的优化。

在core-js@2中,@babel/preset-evn在插件内部有一个data-table,维护了不同浏览器对于特定API的支持,通过这个data-table来实现不同targets按需加载所需要的core-js模块。由于这个compat-table存在一些固有的问题,作者重新维护了一个包,即core-js-compat,用来提供不用目标引擎所需要的core-js的模块信息。

const {
  list,              // array of required modules
  targets,           // object with targets for each module
} = require('core-js-compat')({
  targets: '> 2.5%', // browserslist query
  filter: 'es.',     // optional filter - string-prefix, regexp or list of modules
});

console.log(targets);

/* =>
{
  'es.symbol.description': { ios: '12.0-12.1' },
  'es.array.reverse': { ios: '12.0-12.1' },
  'es.string.replace': { firefox: '63', ios: '12.0-12.1' },
  'es.string.trim': { ios: '12.0-12.1' },
  'es.promise': { firefox: '63' },
  'es.promise.finally': { firefox: '63' },
  'es.array-buffer.slice': { ios: '12.0-12.1' },
  'es.typed-array.int8-array': { ios: '12.0-12.1' },
  'es.typed-array.uint8-array': { ios: '12.0-12.1' },
  'es.typed-array.uint8-clamped-array': { ios: '12.0-12.1' },
  'es.typed-array.int16-array': { ios: '12.0-12.1' },
  'es.typed-array.uint16-array': { ios: '12.0-12.1' },
  'es.typed-array.int32-array': { ios: '12.0-12.1' },
  'es.typed-array.uint32-array': { ios: '12.0-12.1' },
  'es.typed-array.float32-array': { ios: '12.0-12.1' },
  'es.typed-array.float64-array': { ios: '12.0-12.1' },
  'es.typed-array.from': { ios: '12.0-12.1' },
  'es.typed-array.of': { ios: '12.0-12.1' }
}
*/
复制代码

对于core-js@3新的入口文件,下面有一些简单的例子

// 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@3 与 babel

如上面提到的,core-js与babel是高度集成的,babel的集成给core-js的按需加载提供了可能。在babel7.4.0的版本中已经支持core-js@3的版本。

@babel/prest-env

在升级到7.4.0以上的版本以后,既支持core-js@2,也支持core-js@3。所以增加了 corejs 的配置,来控制所需的版本,默认是core-js@2并且会有文字输出提示升级到3的版本。

@babel/prest-env可以通过配置useBuiltIns来根据targets加载@babel/polyfill。

@babel/polyfill的改动

@babel/polyfill是一个简单的包,包含core-js和regenerator-runtime这两个包。当core-js升级到3.0的版本后,将放弃使用@babel/polyfill,因为它只包含core-js 2.0的版本。

所以在@babel/prest-env升级到7.4.0并且使用core-js@3,需要做如下的替换工作

// 安装core-js@3.0 和 regenerator-runtime
yarn add core-js@3
yarn add regenerator-runtime


// babel.config.js
presets: [
  ["@babel/preset-env", {
    useBuiltIns: "entry", // or "usage"
    corejs: 3,
  }]
]


// 入口文件index.js
// before
import "@babel/polyfill";

// after
import "core-js/stable";
import "regenerator-runtime/runtime";

复制代码

@babel/runtime

当使用core-js@3的时候,@babel/transform-runtime会从core-js-pure这个包里去加载对应的polyfill代码,core-js-pure里面的代码不会污染全局变量,适合第三方库的开发。

在@babel/transform-runtime的最新版本中,已经支持core-js@3,需作如下操作。

yarn remove @babel/runtime-corejs2
yarn add @babel/runtime-corejs3

//babel.config.js
plugins: [
  ["@babel/transform-runtime", {
    corejs: 3,
  }]
]

复制代码

改变一

在之前的版本中,@babel/runtime最大的问题就是无法模拟实例上的方法,比如数组的includes方法就无法被polyfill。

但是在core-js@3的版本中,所有的示例方法都可以被polyfill了。

array.includes(something)

↓ ↓ ↓ ↓ ↓ ↓

import _includesInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/includes";
_includesInstanceProperty(array).call(array, something);

复制代码

改变二

core-js@3支持对ECMAScript提案的API进行模拟。

@babel/plugin-transform-runtime的默认配置中,是不会注入对提案的polyfill代码。如果想要支持提案中的API,只需要增加和@babel/preset-env类似的配置项。

plugins: [
  ["@babel/transform-runtime", {
    corejs: { version: 3, proposals: true },
  }]
]
复制代码
new Set([1, 2, 3, 2, 1]);
string.matchAll(/something/g);

↓ ↓ ↓ ↓ ↓ ↓

// without proposals flag
import _Set from "@babel/runtime-corejs3/core-js-stable/set";
new _Set([1, 2, 3, 2, 1]);
string.matchAll(/something/g);


// with proposals: true
import _Set from "@babel/runtime-corejs3/core-js/set";
import _matchAllInstanceProperty from "@babel/runtime-corejs3/core-js/instance/match-all";
new _Set([1, 2, 3, 2, 1]);
_matchAllInstanceProperty(string).call(string, /something/g);

复制代码

展望未来

对老版本浏览器的支持

core-js支持尽量多的浏览器和平台,甚至是IE8-和一些老版本的Firefox浏览器。但是支持如此多的低版本浏览器,必然会造成polyfill文件变大,增大包的体积。

最大的问题主要来自于一些只支持ES3的浏览器,比如IE8-。大多数ES的新特性,都是基于ES5的语法去实现的,这就导致为了使低版本的浏览器能够支持这些新的特性,需要用大量的填充代码去抹平ES5与ES3的差异。

虽然在某些地区IE8还是非常流行,但是为了语言的发展和进步,应该允许某些浏览器退出历史的舞台。core-js@3已经放弃支持IE6,在下个大版本中,core-js@将不再支持IE8,只支持那些基于ES5语法的浏览器。

ECMAScript 模块

core-js的模块都是基于CommonJS规范的。随着ECMAScript模块的发布和普及,core-js应该提供一个ECMAScript模块规范的版本以供选择。

更好的优化polyfill的加载问题

在使用@babel/preset-env的 useBuiltIns:usage 这个配置项是,还是会存在一些问题。比如当项目的文件无法进行静态分析时,需要提供一种方案来进行polyfill的加载。另一个问题是 useBuiltIns:usage 可能会在一个文件头注入数十个core-js的导入语句。当项目中有几百上千个文件的时候,这些注入的语法会占据数量客观的体积。我们需要一个机制来收集所有需要用到的模块,并进行去重操作,最后统一注入到项目里。

对于那些需要支持低版本浏览器的开发人员来说,为了支持IE11这种浏览器,polyfill文件的大小会急剧膨胀。一种解决方案是使用type = module / nomodules属性,生成两个不同的包,一个用来支持现代浏览器,一个用来支持低版本的浏览器,但这并不是一个完美的解决方案;另一种解决方式是提供一个polyfill的服务,根据请求中的UA来判断浏览器的型号,返回这个浏览器需要的polyfill文件, 类似的服务有polyfill.io 。但是polyfill.io的返回并不准确,可用性不是很高。

others

  • 增加对web标准的支持,比如fetch
  • @babel/runtime提供对目标环境的支持,类似@babel/preset-env中targets字段

链接

core-js

core-js@3, babel and a look into the future

@babel/prest-env 7.4.0 Released: core-js 3, static private methods and partial application


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Unity 3D游戏开发(第2版)

Unity 3D游戏开发(第2版)

宣雨松 / 人民邮电出版社 / 2018-9 / 89.00元

Unity 是一款市场占有率非常高的商业游戏引擎,横跨25 个主流游戏平台。本书基于Unity 2018,结合2D 游戏开发和3D 游戏开发的案例,详细介绍了它的方方面面,内容涉及编辑器、游戏脚本、UGUI 游戏界面、动画系统、持久化数据、静态对象、多媒体、资源加载与优化、自动化与打包等。 本书适合初学者或者有一定基础的开发者阅读。一起来看看 《Unity 3D游戏开发(第2版)》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具