使用指南

Babel 工具链是由大量的工具组成的,无论你是 “最终用户” 还是在集成 Babel,这些工具都简化了 Babel 的使用。本文是对这些工具的使用方法的快速介绍,你可以在文档的 “用法” 章节了解到更多信息。

如果你正在使用的是一套框架,Babel 的配置可能会有所不同,也可能已经自动为你配置好了。请参考 交互式配置指南 了解更多信息。

概览

本指南将想你展示如何将 ES2015+ 语法的 JavaScript 代码编译为能在当前浏览器上工作的代码。这将涉及到新语法的转换和缺失特性的修补。

过程

整个配置过程包括:

(1)运行以下命令安装所需的包(package)

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

(2)在项目的根目录下创建一个命名为 babel.config.json 的配置文件(需要 v7.8.0 或更高版本),并将以下内容复制到此文件中:

{
  "presets": [
    [
      "@babel/env",
      {
        "targets": {
          "edge": "17",
          "firefox": "60",
          "chrome": "67",
          "safari": "11.1"
        },
        "useBuiltIns": "usage",
        "corejs": "3.6.5"
      }
    ]
  ]
}

上述浏览器列表仅用于示例。请根据你所需要支持的浏览器进行调整。参见 此处 以了解 @babel/preset-env 可接受哪些参数。

如果你使用的是 Babel 的旧版本,则文件名为 babel.config.js。

const presets = [
  [
    "@babel/env",
    {
      targets: {
        edge: "17",
        firefox: "60",
        chrome: "67",
        safari: "11.1",
      },
      useBuiltIns: "usage",
      corejs: "3.6.4",
    },
  ],
];

module.exports = { presets };

(3)运行此命令将 src 目录下的所有代码编译到 lib 目录:

./node_modules/.bin/babel src --out-dir lib

你可以利用 npm@5.2.0 所自带的 npm 包运行器将 ./node_modules/.bin/babel 命令缩短为 npx babel

CLI 命令行的基本用法

你所需要的所有的 Babel 模块都是作为独立的 npm 包发布的,并且(从版本 7 开始)都是以 @babel 作为冠名的。这种模块化的设计能够让每种工具都针对特定使用情况进行设计。

下面我们着重看一下 @babel/core 和 @babel/cli

核心库

Babel 的核心功能包含在 @babel/core 模块中。

通过以下命令安装:

npm install --save-dev @babel/core  

你可以在 JavaScript 程序中直接 require 并使用它:

const babel = require("@babel/core");

babel.transformSync("code", optionsObject);

作为一名最终用户,你可以还需要安装其他工具作为 @babel/core 的使用接口并很好地集成到你的开发流程中。

即便如此,你仍然需要查看其文档并了解可用的参数,其中很多参数也可以通过其他工具进行设置。

CLI 命令行工具

@babel/cli 是一个能够从终端(命令行)使用的工具。下面是其安装命令和基本用法:

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

./node_modules/.bin/babel src --out-dir lib

这将解析 src 目录下的所有 JavaScript 文件,并应用我们所指定的代码转换功能,然后把每个文件输出到 lib 目录下。

由于我们还没有指定任何代码转换功能,所以输出的代码将与输入的代码相同(不保留原代码格式)。我们可以将我们所需要的代码转换功能作为参数传递进去。

上面的示例中我们使用了 –out-dir 参数。你可以通过 –help 参数来查看命令行工具所能接受的所有参数列表。

但是现在对我们来说最重要的是 –plugins 和 –presets 这两个参数。

插件和预设(preset)

代码转换功能以插件的形式出现,插件是小型的 JavaScript 程序,用于指导 Babel 如何对代码进行转换。

你甚至可以编写自己的插件将你所需要的任何代码转换功能应用到你的代码上。

例如将 ES2015+ 语法转换为 ES5 语法,我们可以使用诸如 @babel/plugin-transform-arrow-functions 之类的官方插件:

npm install --save-dev @babel/plugin-transform-arrow-functions

./node_modules/.bin/babel src --out-dir lib --plugins=@babel/plugin-transform-arrow-functions

现在,我们代码中的所有箭头函数(arrow functions)都将被转换为 ES5 兼容的函数表达式了:

const fn = () => 1;

// converted to

var fn = function fn() {
  return 1;
};

这是个好的开始!但是我们的代码中仍然残留了其他 ES2015+ 的特性,我们希望对它们也进行转换。

我们不需要一个接一个地添加所有需要的插件,我们可以使用一个 “preset” (即一组预先设定的插件)。

就像插件一样,你也可以根据自己所需要的插件组合创建一个自己的 preset 并将其分享出去。J对于当前的用例而言,我们可以使用一个名称为 env 的 preset。

npm install --save-dev @babel/preset-env

./node_modules/.bin/babel src --out-dir lib --presets=@babel/env

如果不进行任何配置,上述 preset 所包含的插件将支持所有最新的 JavaScript (ES2015、ES2016 等)特性。

但是 preset 也是支持参数的。

我们来看看另一种传递参数的方法:配置文件,而不是通过终端控制台同时传递 cli 和 preset 的参数。

配置

根据你的需要,可以通过几种不同的方式来使用配置文件。另外,请务必阅读我们关于如何 配置 Babel 的深入指南以了解更多信息。

现在,我们首先创建一个名为 babel.config.json 的文件(需要 v7.8.0 或更高版本),并包含如下内容:

{
  "presets": [
    [
      "@babel/env",
      {
        "targets": {
          "edge": "17",
          "firefox": "60",
          "chrome": "67",
          "safari": "11.1"
        }
      }
    ]
  ]
}

现在,名为 env 的 preset 只会为目标浏览器中没有的功能加载转换插件。

语法都已经清楚了,接下来我们看看 polyfills 。

Polyfill

从 Babel 7.4.0 版本开始,这个软件包已经不建议使用了,建议直接包含 core-js/stable (用于模拟 ECMAScript 的功能)和 regenerator-runtime/runtime 需要使用转译后的生成器函数):

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

@babel/polyfill 模块包含 core-js 和一个自定义的 regenerator runtime 来模拟完整的 ES2015+ 环境。

这意味着你可以使用诸如 Promise 和 WeakMap 之类的新的内置组件、 Array.from 或 Object.assign 之类的静态方法、 Array.prototype.includes 之类的实例方法以及生成器函数(generator functions)(前提是你使用了 regenerator 插件)。

为了添加这些功能,polyfill 将添加到全局范围(global scope)和类似 String 这样的原生原型(native prototypes)中。

对于软件库/工具的作者来说,这可能太多了。如果你不需要类似 Array.prototype.includes 的实例方法,可以使用 transform runtime 插件而不是对全局范围(global scope)造成污染的 @babel/polyfill。

更进一步,如哦你确切地指导你所需要的 polyfills 功能,你可以直接从 core-js 获取它们。

由于我们构建的是一个应用程序,因此我们只需安装 @babel/polyfill 即可:

npm install --save @babel/polyfill

注意,使用 –save 参数而不是 –save-dev,因为这是一个需要在你的源码之前运行的 polyfill。

幸运的是,我们所使用的 env preset 提供了一个 “useBuiltIns” 参数,当此参数设置为 “usage” 时,就会加载上面所提到的最后一个优化措施,也就是只包含你所需要的 polyfill。

使用此新参数后,修改配置如下:

{
  "presets": [
    [
      "@babel/env",
      {
        "targets": {
          "edge": "17",
          "firefox": "60",
          "chrome": "67",
          "safari": "11.1"
        },
        "useBuiltIns": "usage"
      }
    ]
  ]
}

Babel 将检查你的所有代码,以便查找目标环境中缺失的功能,然后只把必须的 polyfill 包含进来。

示例代码如下:

Promise.resolve().finally();

将被转换为(由于 Edge 17 没有 Promise.prototype.finally):

require("core-js/modules/es.promise.finally");

Promise.resolve().finally();

如果我们不使用将 “useBuiltIns” 参数设置为 “usage” (默认值是 “false”)的 env 预设的话,那么我们必须在所有代码之前利用 require 加载 一次 完整的 polyfill。

例如:

{
  "presets": [
    [
      "@babel/env",
      {
        "targets": {
          "edge": "17",
          "firefox": "60",
          "chrome": "67",
          "safari": "11.1"
        },
        "useBuiltIns": "entry"
      }
    ]
  ]
}

Then import core-js (to polyfill ECMAScript features) and regenerator runtime (needed only if you are transpiling generators) first, in our entry file to emulate a full ES2015+ environment since @babel/polyfill has been deprecated:

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

总结

我们使用 @babel/cli 从终端运行 Babel,利用 @babel/polyfill 来模拟所有新的 JavaScript 功能,而 env preset 只对我们所使用的并且目标浏览器中缺失的功能进行代码转换和加载 polyfill。

有关针对构建系统、IDE 等设置 Babel 的详细信息,请参阅 交互式设置指南。

参考资料

https://www.babeljs.cn/docs/usage