在开发web应用时编写JavaScript时,必须考虑浏览器的兼容性,以及没有实现特性时会发生什么。有些人会建议干脆不要使用它,如果我们在构建复杂的东西,这是一种痛苦的体验。

庆幸的是,一些工具允许我们不再担心支持什么,而是尽可能编写最好的代码。它们被称为transpilers。transiler是一种以源代码作为输入并生成新的源代码作为输出的工具,它具有不同的语法,但是语义上尽可能接近于原始代码,或者在理想情况下等效于原始代码。

Babel几乎是将现代JavaScript (ES2015+)转换为在旧浏览器中运行的兼容实现的标准转换器。如果您只想专注于编写JavaScript,那么它是一个完美的解决方案。

尽管Babel的主要目标是为旧(有时是当前)浏览器翻译ECMAScript (ES)的最新标准,但它还可以做更多工作。有一个预置和插件的生态系统,使得添加非标准特性成为可能。每个插件都为您的代码提供了一个新的特性/转换,而预置只是插件的集合。

准备开始

大多数情况下,CLI是最快速、最简单的入门方法。

首先安装babel:

要确保安装了Node.js

接下来,我们在package.json中添加一个npm script命令:

"scripts": {
  "build": "babel src -d dist"
}
编译src源文件,输出到dist目录

运行npm脚本:

npm run build

等等! 在运行Babel之前,我们必须安装将转换代码的插件。最简单和最快的方法是添加Env preset,它根据指定的浏览器选择适当的插件。可使用:

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

在项目根目录下创建 .babelrc, 并配置preset:

{
  "presets": ["env"]
}

.babelrc作为babel配置文件,主要使用它来设置presets和plugin,还有很多选项可用。您可以在Babel API页面中查看。

注意,取决于操作系统,默认情况下以.开头的文件会被隐藏。如果这对您来说是有问题的(或者如果您只是喜欢更少的文件),您可以将Babel设置放入package.json文件,如下所示:

{
  "name": "babel-test",
  "version": "1.0.0",
  "babel": {
    // config
  }
}

执行Babel

src/main.js 写入:

let a = 1;
let b = 2;
[a, b] = [b, a];
console.log(a);
console.log(b);

执行build命令来运行编译过程:

npm run build

将转换后的代码输出到dist/main.js。

dist/main.js 最终生成的内容:

"use strict";

var a = 1;
var b = 2;
var _ref = [b, a];
a = _ref[0];
b = _ref[1];

console.log(a);
console.log(b);

你会看到let已被var替换,Babel引入了一个临时变量(由下划线表示)辅助交换。

默认情况下,如果不向preset添加任何选项,它将加载所有转换。

你也可以指定目标浏览器:

{
  "presets": [
    ["env", {
      "targets": {
        "browsers": ["last 2 versions", "safari >= 7"]
      }
    }]
  ]
}

这将加载所需的转换,以支持每个浏览器的最新两个版本和大于或等于版本7的Safari。您可以在Browserlist中找到可用选项。

Babel 生态

如果希望包含的每个特性都将以插件的形式出现。看一些ES2015的例子包括:

查看完整的plugin列表

如果不想一个一个地包含所有插件。因此,有一些预先提供的presets,简化每个插件的安装过程。

三个官方presets是:

Env是最常用的,也是我们这里用的。它自动加载所有必要的转换,使您的代码兼容指定的浏览器。

React用于转换React项目中的代码,主要是增加了Flow的注解和JSX的兼容性。

Flow用于清理Flow注释中的代码。

Babel Polyfill

有些JavaScript特性无法进行语法转换,通常是因为没有等价的功能——例如Promises和generator函数。

这些特性必须在浏览器中由一个库实现,以便在代码中使用,这就是polyfill的工作。

高级用法

Babel还可以用于转换语言中尚未实现的特性。一个很好的例子是类字段建议(目前处于TC39阶段3:candidate)。这在React开发人员中尤其流行,因为它消除了将方法显式绑定到特定组件的必要性,还意味着可以将组件的状态声明为类字段(潜在地消除了对构造函数的需要)。

如果想使用类字段,需要添加babel-plugin-transform-class依赖项:

npm install --save-dev babel-plugin-transform-class-properties

.babelrc文件修改如下:

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

你可以使用class:

class App extends Component {
  state = { count: 0 };

  incCount = () => {
    this.setState(ps => ({ count: ps.count + 1 }));
  };

  render() {
    return (
      <div>
        <p>{ this.state.count }</p>
        <button onClick={this.incCount}>add one</button>
      </div>
    );
  }
}

而且不止于此。您还可以使用Babel向该语言添加您自己的新特性,推荐阅读理解通过构建您自己的Babel插件

其它

编写现代web应用有时需要的不仅仅是JavaScript中可用的特性。其他语言也可以翻译成兼容的JavaScript,但也可以实现其他有用的特性。

最流行的选项是TypeScript,它实现了现代的ES特性,但也添加了其他特性,尤其是在类型安全方面。

另一个极端是,在不同的类别中有完全不同的语言,从函数式语言(如PureScript)到面向对象语言(如Dart)。

最后

Babel是编写现代web应用的一个很好的选择,同时还提供所有开发人员都能理解的JavaScript,能运行于各种浏览器。

Babel不仅可以在浏览器和Node.js等平台上将ES2015+转换为es5,还可以添加不属于标准的新特性。再npm网站可以找到所有可用的 pluginpresets

随着JavaScript的发展,浏览器厂商需要一段时间来实现最新的特性。使用Babel可以写最新的JavaScript,而不用考虑运行环境是否支持。

happy learning!