// 输入:
class Circle {}
// 输出:
function _classCallCheck(instance, Constructor) {
//...
}
var Circle = function Circle() {
_classCallCheck(this, Circle);
};
// 输入:
const p = Promise.resolve()
// 输出:
var _promise = require("@babel/runtime-corejs2/core-js/promise");
var _promise2 = _interopRequireDefault(_promise);
var p = _promise2.default.resolve();
自从接触
ES2015
开始,babel
就一直在用,每个项目都在用。每次初始化项目后,.babelrc
和@babel/core
、@babel/cli
、@babel/preset-env
、@babel/transform-runtime
等等信手拈来,但是每次想要区别core-js
、@babel/poly-fill
、@babel/runtime
、@babel/plugin-transform-runtime
、@babel/preset-env
,却又含糊不清,索性来一次整理。我们都知道,ES的每次标准公布,都会有许多新的特性,而这些特性无非分为两部分,一部分是
新语法
,如箭头函数
、解构赋值
、扩展运算符
、for...in
、for...of
、class
、async/await
等,另一部分是API扩展
,如Promise
、Map
、Set
、Array.from
、String.prototype.includes
等。在低版本的浏览器中要使用高版本的
ES特性
,就需要对其代码进行转换。对于新语法
,需要通过语法转换,比如将箭头函数
转化为普通函数
,将赋值结构
转换成单独取值
,将扩展运算符
转换成Object.assign
等实现,而这就是babel
的核心工作。对于新API
,我们是可以通过JavaScript
原有的语法去实现的,实现类似功能的库叫做polyfill
。core-js
以模块化方式实现了ES6+的标准API,包括
Promise
、Symbol
、Map
、Set
等,还有各种原型链上的扩展,如String.prototype.inclues
、Array.prototype.find
等。说白了就是polyfill
,对于箭头函数
、async/await
等语法,自然是无能为力的。我们可以通过引入直接使用:
当然,这么做会直接污染全局环境,例如
Promise
会挂在到window
上,find
会挂在到Array.prototype
上,也可以通过命名空间方式引入:@babel/polyfill
从源码中可以看到,
@babel/polyfill
就是简单地直接引用core-js
和regenerator-runtime
。因此,它会将扩展的API直接挂载到全局(window)和对应的原型(prototype)上,但是这样会导致一些问题:使用方式很简单,写在入口文件开头:
@babel/plugin-transform-runtime
可以在一定程度上替换
@babel/polyfill
来使用,主要解决了两个问题:避免产生多次的helper函数。
babel
在对新语法
转换过程当中,会借助一些helper函数
来实现,比如class
语法:这里的
_classCallCheck
每次转换class
语法都会产生,数量多起来极大影响最终的代码体积。为了解决这个问题,有个@babel/runtime
专门封装了这些helper函数
。通过@babel/plugin-transform-runtime
将这些helper函数
的引用替换为从@babel/runtime
中引入。解决
@babel/polyfill
中污染全局环境和体积过大的问题。@babel/plugin-transform-runtime
中维护了一份API和core-js特性模块间的映射,可以根据具体使用情况,按需自动引入这些core-js
中的特性模块。但是,为了防止污染现有的运行环境,对于实例函数(如
Array.prototype.find
)并不支持。@babel/preset-env
在了解
@babel/preset-ev
先说说babel
的编译过程以及plugin
和preset
的概念。babel-core
作为的编译过程主要分为三个步骤:@babbel/parser
将代码转换为AST
。babel
本身不具备代码编译转换功能,而是依赖于一个个plugin
来进行处理,转换过后的代码仍然是AST
。@babel/generator
将AST
转换为JS代码。所以说,
plugin
中实现了具体的转换功能。比如要将箭头函数
转化为普通函数,就需要@babel/plugin-transform-arrow-functions
,要将class
语法转化为函数实现,就需要@babel/plugin-transform-classes
。而
preset
则代表一组plugin
。比如需要转换jsx
的语法,只需要@babel/preset-react
就行了,它已经包含了@babel/plugin-transform-react-jsx
、@babel/plugin-transform-react-display-name
、@babel/plugin-transform-react-jsx-source
、@babel/plugin-transform-react-jsx-self
。同理
@babel/preset-env
也代表了一组plugin
。通过默认的配置,我们就能够使用ES最新规范中的语法,当然也可以通过配置来达到你需要的效果。总结
最后简单总结一下:
@babel/polyfill
为运行环境提供能完整的ES API
,但是体积较大,新的语法如环境不支持还是不支持。@babel/plugin-transform-runtime
能够按需自动引入ES API
,能够有效控制体积,但是不支持函数实例方法,不对语法进行转换。@babel/preset-env
集成若干plugin
,能将ES5+
语法转换成ES5
语法,不集成ES API
的polyfill。