十五分钟的Babel入门指南

什么是Babel

Babel是将ES6以及以上版本的代码转换为ES5代码的工具,用于适应低版本浏览器。简单来说,功能有以下三个:

  • 语法转换
  • 通过Polyfiil的方式在目标环境中添加缺失的特性(通过 @babel/polyfill 模块)
  • JS源码转换

使用基本环境安装

npm install --save-dev @babel/core @babel/cli

@babel/core

包含了babel的核心功能。

@babel/cli

帮助我们在终端使用babel命令的工具。

配置babel

一般使用babel.config.js或者.babelrc文件作为配置文件。

其中,主要的两个属性有:

  • plugins(插件):用于转换我们的代码。
  • presets(预设):组合插件包,方便使用。

关于plugins

.babelrc为例:

{
    "plugins":["transform-decorators-legacy", "transform-class-properties"],
    "presets":[]
}

可以直接在数组中加入插件的名称,babel会检查他是否被安装到node_module目录下。

也可以指定插件的相对或绝对路径。


如果插件前缀为babel-plugin-,可以使用简称:

{
    // 实际上是同一个插件
    "plugins": ["myPlugin","babel-plugin-myPlugin"]
}
{
    // 冠名插件也同样适用
    "plugins": ["@org/babel-plugin-name","@org/name"]
}

插件的执行顺序有两点:

  • 插件在presets之前运行。
  • 插件是从左到右执行。
{
    "plugins":["transform-decorators-legacy", "transform-class-properties"],
}

先执行transform-decorators-legacy,后执行transform-class-properties


插件可以进行传参,参数对象与插件名字共同组成一个数组。

{
  "plugins": [
    [
      "transform-async-to-module-method",
      {
        "module": "bluebird",
        "method": "coroutine"
      }
    ]
  ]
}

关于presets

presets就是一堆插件的组合,方便我们在编译的时候直接使用。

{
    "presets": ["babel-preset-myPreset"]
}

类似于plugins,直接在presets参数中设置就可以,babel会自动检查该预设是否已经安装到node_module下。


如果preset名称前缀为babel-preset-,可以使用简称:

{
    // 这两个是一样的
    "presets": ["myPreset","babel-preset-myPreset"]
}

与plugins不同,presets的执行顺序是从后往前的。

{
  "presets": [
    "a",
    "b",
    "c"
  ]
}

会按c→b→a的顺序来执行。这是为了确保向后兼容。


与plugins一样,presets也可以传递参数,参数对象和预设名共同组成一个数组:

{
  "presets": [
    ["@babel/preset-env", {
      "loose": true,
      "modules": false
    }]
  ]
}

常见的babel插件/预设

babel-loader

这其实不算一个插件或者预设,但是在项目中经常会使用到,于是把它添加到这里一并写。

在Webpack中使用的loader配置,可以在options参数中配置plugins和presets。

module: {
  rules: [
    {
      test: /\.js$/,
      exclude: /(node_modules|bower_components)/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env']
        }
      }
    }
  ]

babel-preset-env

babel的一个预设包,可以根据配置的目标浏览器或运行环境来按需自动将ES6+的代码转换为ES5。

{
  "presets": [
    [
      "env",
      // 以下为参数配置
      {
        // 将ES6 module转换为其他规范
        "modules": false,
        // 为polyfills 应用 @babel/preset-env
        "useBuiltIns": true,
        // 目标环境配置
        "targets": {"browsers": ["last 2 versions", "safari >= 7", "ie>=9"]}
      }
    ],
  ...
}

可参考:https://cloud.tencent.com/developer/article/1470739

babel-preset-stage-0

是关于babel在不同阶段ES2015+语法提案支持的转码规则模块。

提案一般分为以下阶段:

  • stage-0:设想,功能范围最大,包含后面的几个阶段。(所以我们一般使用stage-0预设)
  • stage-1:建议
  • stage-2:草案
  • stage-3:候选
  • stage-4:完成

在Babel7.0之后这个预设似乎已经不被再支持。


Polyfill

Babel默认只转换新的JavaScript语法,而不转换新的API(如Iterator、Generator、Set、Map等),以及一些定义在全局对象上的方法都不会转码。如果想要使用这些新的方法和对象,就需要使用babel-polyfill为当前环境提供一个垫片。它可以帮助模拟一整个ES2015+的运行环境。

需要注意的是,它是通过向全局对象和内置对象的prototype上添加方法来实现的,所以会造成全局变量空间污染

使用@babel/polyfill的方式

// 在js文件中
import 'babel-polyfill'

// 在webpack.config.js中
entry: {
    main: ['@babel/polyfill', './main.js']
},

// 在.babelrc中通过@babel/preset-env进行设置,这样可以不用引用@babel/polyfill
{
	"presets": [["@babel/preset-env", {"useBuiltIns": "usage", "corejs": 2}]],
}

除了@babel/polyfill以外,提供垫片的方式还有使用babel-runtimebabel-plugin-transform-runtime插件。

@babel/polyfill虽然方便解决了新语法中API不转换的问题,但是它污染了全局环境,并且在每一个打包出来的文件中添加重复的辅助代码,这样就会导致编译后项目代码的体积很大。@babel/polyfill便于我们开发第三方应用,但如果我们需要发布代码或者库的话,就会导致问题。

babel-runtime是单独的用于代码编译的辅助函数包,由于没有额外加工,所以使用的时候需要自己在每一个文件中require引入。但如果许多文件中都要使用同一个模块,这种方式就显得很繁琐。

babel-plugin-transform-runtime就是为了解决上面的问题而产生的,它会帮助我们自动并且按需引入babel-runtime中的工具函数。这样可以减小项目体积。

babel-runtimebabel-plugin-transform-runtime一般会同时安装,同时使用。

// 无参数
{
  "plugins": ["@babel/plugin-transform-runtime"]
}

// 有参数
{
  "plugins": [
    [
      "@babel/plugin-transform-runtime",
      {
        "absoluteRuntime": false,
        "corejs": false,
        "helpers": true,
        "regenerator": true,
        "useESModules": false,
        "version": "7.0.0-beta.0"
      }
    ]
  ]
}

实例

下面是一个典型的.babelrc配置文件(vue-cli中的):

{
  // presets预设配置
  "presets": [
    // 使用babel-presets-env
    ["env", {
      // 是否将ES6 module转换为其他规范
      "modules": false,
      // 目标环境
      "targets": {
        // 支持的浏览器版本设置,具体可以参看Browserslist
        "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
      }
    }],
    // 使用babel-presets-stage-2
    "stage-2"
  ],
  // plugins插件设置
  "plugins": ["transform-vue-jsx", "transform-runtime"],
  // 编译过程中是否产生注释
  "comments": false,
  // 在特定环境中设置的特定配置,会覆盖上面的配置
  // env的值将会从process.env.BABEL_ENV中获取,没有的话查找process.env.NODE_ENV,都没有的话设置为development
  "env": {
    "test": {
      // 特定环境下使用的预设
      "presets": ["env", "stage-2"],
      // 特定环境下使用的插件
      "plugins": ["transform-vue-jsx", "transform-es2015-modules-commonjs", "dynamic-import-node"]
    }
  }
}

参考资料:

  • https://juejin.im/post/5e5b488af265da574112089f
  • https://babeljs.io/docs/en/next/
  • https://www.cnblogs.com/L-xmin/p/12493824.html
  • https://zhuanlan.zhihu.com/p/29058936
  • https://cloud.tencent.com/developer/section/1489428
  • https://www.cnblogs.com/ye-hcj/p/7071850.html

此博客作为学习过程中笔记,知识浅薄,如有错漏,请指出(鞠躬)。

你可能感兴趣的:(关于前端)