对于babel的几点理解

2,944 阅读5分钟

babel的作用

babel到底是用来做什么的?简单来讲,babel就是用来做语法编译的,它可以将一些es6+的高级语法编译为浏览器可以识别的es5。通常,我们可以在通过配置presets和plugins来规定babel要怎么编译你的代码。presets其实是一些列plugin的集合,是预先设置好的一系列编译规则。babel配置中plugin和presets的执行顺序,先执行plugin的配置项,在执行presets的配置项,plugin配置项是按照声明顺序执行,presets配置项按照证明逆序执行。

babel7以后的相关改变

在babel的版本7.0之后,低版本的node将不在支持了,要求node的版本大于6,并且,对于presets的相关配置,将会废除stage-x这种用法,es201x这种用法也不再推荐使用,官方推荐使用env的方式。babel包的名称也发声了改变,将所有babel-*的包重命名为@babel/*的方式,例如babel-preset-env ——> @babel/preset-env。

babel的相关包及其作用

包名 作用 备注
babel-loader webpack的插件,在webpack打包时用来加载代码 webpack使用
@babel/core babel的核心包,包含语法转换的API,主要用转化es6+的语法 用于语法转换
@babel/polyfill babel垫片,主要作用是兼容es6+新特性(如promise,set等),本质是由 core-js 和 regenerator-runtime 组成的。 babel7.4 以后官方以不推荐使用 用core-js3代替
core-js 给低版本浏览器提供es6+新特性接口的库。分为 core-js@2和@core-js@3
regenerator-runtime regenerator-runtime模块来自facebook的regenerator模块,主要作用是生成器函数、async、await函数经babel编译后,regenerator-runtime模块用于提供功能实现
@babel/helpers 用来把@babel/core处理的代码中插入的帮助函数当做一个模块引入,减小代码的体积
@babel/plugin-transform-runtime 用来引入垫片的插件,
@babel/runtime 包含@babel/helpers 和 regenerator-runtime
@babel/runtime-corejs2 由 core-js@2、@babel/helpers 和 regenerator-runtime 组成 @babel/runtime-corejs2不能转化对象实例的方法
@babel/runtime-corejs3 由 core-js@3、@babel/helpers 和regenerator-runtime 组成 @babel/runtime-corejs3可以转化对象实例的方法

@babel/polyfill和@babel/plugin-transform-runtime

babel只能转换es6+的新语法,比如将箭头函数转换为浏览器能识别的函数方法,但是。我们知道,es6中除了新增加新的语法外,还增加了许多新特性,比如promise,set,map,async,await等新的api,浏览器对这些新的特性是不能够识别的,所以,我们还需要在代码转换的时候去实现这些新特性。babel为我们提供了两套方案去实现这些新特性。一种是@babel/polyfill的方式,另一种是@babel/plugin-transform-runtime的方式。总的来说,只要我们能够满足有core-js(babel中对于新特新的api实现的包)和regenerator-runtime(主要是async,await实现的包)就行了,就可以兼容各种浏览器了。当然,还有@babel/helpers,这并不是必须的,不过它可以做一些事情,把@babel/core往代码中插入的帮助函数当做模块引入,每个文件只需要调用这个模块就可以了,这可以让我们的代码体积更小。下面会基于babel7.4以上的版本具体说一下两种方案的具体实现方案。

@babel/polyfil

在babel7.4以上推荐用core-js3和regenerator-runtime代替@babel/polyfil,所以用之前需要安装core-js3和regenerator-runtime为生产依赖。然后只需要在.babelrc文件中做如下配置

{
     "presets": [
        ["@babel/preset-env",{
            "target":{},
            "useBuiltIns":"usage",
            "corejs":3,
            "modules":false
          }
        ]
    ],
    "plugins": [
    ]
}

配置参数:

  • target:babel转换代码最终的执行环境,根据目标环境判断是否需要对语法进行转换。
  • modules:用来转换es6的模块语法,值有amd,umd,systemjs,commonjs,cjs,auto,false,默认值为auto,如果需要webpack的tree shaking的一些特性,需要将此参数设为false
  • corejs:设置corejs的版本号,2或者3
  • useBuiltIns:false,usage,entry,默认值为false,此参数用来设置垫片的引入方式。
    • false:这种情况下corejs属性无效,此时仅根据target属性判断后做相应的语法转换
    • usage:设置为usage时会自动按需引入垫片(官方推荐)
    • entry:设置为entry时,需要自己在入口处手动引入垫片,全部引入
    import"core-js/stable" 
    import "regenerator-runtime/runtime"

通过这种方式引入垫片,因为是在全局下和对象的原型链上实现的新特性,所以会污染全局环境和对象的原型链。此外,core-js3实现了对象实例的方法。

@babel/plugin-transform-runtime

这是另一种引入垫片的方案,这种方式是通过@babel/plugin-transform-runtime插件自动按需的引入垫片,需要安装@babel/runtime-corejs为生产依赖。配置如下:

{
    "presets": [
        "@babel/preset-env"
    ],
    "plugins": [
        ["@babel/plugin-transform-runtime",{
         "corejs":3,
         "useESModules":false
       }],
    ]
  }
  • corejs:默认值为false,为fasle时需要安装@babel/runtime为生产依赖,此时因为没有corejs。所以只做语法转换。也可以为2或者3,需安装对应的@babel/runtime-corejs2或@babel/runtime-corejs3为生产依赖。2和3的区别在于,core-js2没有对对象实例方法的实现,core-js3则实现了。
  • useESModules:是否对文件使用ES的模块语法,默认值为false。如果需要webpack的tree shaking的一些特性,需要将此参数设为true。

通过@babel/plugin-transform-runtime这种方式来添加垫片,可以避免污染全局变量环境,并且也是自动按需引入,core-js3对于对象实例的方法也有实现。是一个不错的选择。