首先,作为入门的话,Babel的用户手册是个很不错的选择,里面基本覆盖了Babel使用的各方面。所以下面主要是我学习Babel的一些笔记,姑且当作是一篇入门吧。
Babel是什么
按照Babel官网的说法,Babel是一个Javascript编译器。它可以把用最新标准编写的Javascript代码编译成现在的浏览器或者node环境下能运行的代码,这个过程叫做“源码到源码”编译,又称转译(transpiling)。通过这个方式,我们就可以提前使用下一代的标准和特性进行编码,然后在现在的环境下运行。
安装Babel
通常我们使用Babel的babel-cli
工具在命令行下进行文件的编译。我们可以对babel-cli进行全局安装,也可以把它安装到项目里。这里我选择了把它安装到项目里。这样做的好处是:
不同的项目可能会使用不同版本的Babel,使用全局的话只能使用一致的版本
方便项目的部署,使用全局安装的话意味着对环境有个隐式的依赖。
除了
babel-cli
,还有其他使用Babel的方式,具体可以看用户手册。
下面我们开始安装babel-cli
。首先新建一个工作目录,并创建package.json
文件:
$ npm init -y
安装babel-cli
:
$ npm install --save-dev babel-cli
安装完我们可以这样运行:
$ ./node_modules/babel-cli/bin/babel.js -V
6.11.4 (babel-core 6.11.4)
但是这样运行很不方便,我们可以通过npm scripts
来运行Babel。在package.json
文件里,我们增加scripts
字段,并添加一个脚本:
{
"scripts": {
"build": "babel src -d lib"
},
"devDependencies": {
"babel-cli": "^6.11.4"
}
}
这里增加了一条名字为build
的脚本,命令的内容是把src
里的文件通过Babel转译到lib
目录里。然后我们可以通过以下命令运行脚本:
$ npm run build
当然,现在运行这个命令会报错,因为我们并没有src
文件夹。下面我们正式进入正题。
Babel的基础使用
转译初探
首先我们创建src
目录,然后创建一个js文件index.js
:
[1,2,3].map(n => n + 1);
然后运行npm run build
命令,就会看到lib
文件夹里多了一个转译后的文件index.js
。但是打开来看会发现这个转译后的文件跟源文件并没有区别。因为Babel需要你通过插件(Plugin)
或者预设(presets)
告诉它做什么。例如我们可以通过babel-preset-es2015
告诉Babel把ES2015的文件转译成ES5。这也是Babel最常用的一个用法之一。
配置文件
要使用插件或者预设(相当于一组插件),我们需要在Bable的配置文件里面进行配置。有两个方式进行配置。
第一个方式是通过.babelrc
文件:
{
"presets": [],
"plugins": []
}
第二个方式是使用package.json
文件:
{
"name": "my-package",
"version": "1.0.0",
"babel": {
"presets": [],
"plugins": []
}
}
使用预设
上面说过,预设就是一组插件的集合,例如预设babel-preset-es2015
就是把一堆跟ES2015有关的插件组合起来提供编译ES2015代码为ES5代码的功能。下面我们开始使用babel-preset-es2015
预设来把ES2015转译成ES5。
首先我们安装这个预设:
$ npm install --save-dev babel-preset-es2015
然后在配置文件里添加这个预设:
{
"presets": [
"es2015"
],
"plugins": []
}
最后我们再次运行一次npm run build
命令,再次打开lib/index.js
文件,我们会看到代码已经被编译成ES5的语法:
"use strict";
[1, 2, 3].map(function (n) {
return n + 1;
});
Babel的执行
Polyfill
像上面那段转译后的代码我们可以直接使用在当前的环境下,但是并不是所有转译后的文件我们都只能直接使用,因为虽然Babel可以编译目前几乎所有的ES2015语法,但是一些新的API可能在当前的Javascript环境下无法支持。例如下面的代码(假设文件为lib/index.js
):
function addAll() {
return Array.from(arguments).reduce((a, b) => a + b);
}
转译后会变成:
function addAll() {
return Array.from(arguments).reduce(function(a, b) {
return a + b;
});
}
可以看到语法上已经转译成ES5了,但是并不是所有的Javascript环境都支持Array.from
,例如我们在IE上运行如下页面:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script src="lib/index.js"></script>
<script>
console.log(addAll(1, 2, 3, 4, 5));
</script>
</body>
</html>
可能会报以下的错误:
对象不支持“from”属性或方法
Babel的解决方法就是使用Polyfill技术(使用了core-js和regenerator),通过在当前的运行环境模拟不存在的API来达到使用新API的目的。
首先我们安装babel-polyfill
:
$ npm install --save babel-polyfill
注意这里使用的是--save
而不是--save-dev
,因为我们需要在代码里引入babel-polyfill
。我们需要在文件顶部导入它:
import "babel-polyfill";
在添加这句代码后,上面的代码在转译后会变成下面这个样子:
"use strict";
require("babel-polyfill");
function addAll() {
return Array.from(arguments).reduce(function (a, b) {
return a + b;
});
}
因为Babel编译时默认使用的是CommonJS的模块规范,所以会看到转译后的代码使用了require
方法来加载babel-polyfill
。这个在node环境下运行没有问题,但是在浏览器环境下运行就会报错,因为浏览器目前还不原生的支持模块的加载。那在浏览器下怎么使用babel-polyfill
呢?
我们可以把babel-polyfill
通过外部js的方式加载进来,而不是在js代码里进行引入:
<script src="node_modules/babel-polyfill/dist/polyfill.min.js"></script>
<script src="lib/index.js"></script>
但是如果你打算在项目里使用模块,上面明显不是很好的解决方案。下面我们看看如果解决在浏览器环境下模块的加载问题。
使用模块
要在浏览器环境下加载依赖模块,有很多方式,例如使用webpack
或者browserify
之类的打包工具(建议的方式,但是这里我们先不涉及)。或者我们可以使用浏览器端的模块加载器进行加载,例如我们使用AMD模块规范进行编译,然后用RequireJS进行加载。下面我使用SystemJS来做例子。
首先我们安装es2015-modules-systemjs
插件:
$ npm install babel-plugin-transform-es2015-modules-systemjs
然后修改配置文件,在plugins
里添加插件:
{
"plugins": ["transform-es2015-modules-systemjs"]
}
我们修改下lib/index.js
,把addAll
方法导出为模块的方法:
import "babel-polyfill";
export function addAll() {
return Array.from(arguments).reduce((a, b) => a + b);
}
再次对文件进行编译,编译后的lib/index.js
变成这样:
"use strict";
System.register(["babel-polyfill"], function (_export, _context) {
"use strict";
return {
setters: [function (_babelPolyfill) {}],
execute: function () {
function addAll() {
return Array.from(arguments).reduce(function (a, b) {
return a + b;
});
}
_export("addAll", addAll);
}
};
});
然后我们需要在HTML里引入system.js
。由于SystemJS依赖于Promise
,它会加载目录下system-polyfills.js
文件,所以我们需要确保这个文件的存在。在加载system.js
后,我们就可以使用SystemJS进行模块的加载了:
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script src="system.js"></script>
<script>
System.config({
baseURL: './lib',
map: {
'babel-polyfill': './node_modules/babel-polyfill/dist/polyfill.min.js'
}
});
System.import('index.js').then(function(m) {
console.log(m.addAll(1, 2, 3, 4, 5)); // 15
});
</script>
</body>
</html>
出于性能的考虑,也可以用像Bluebird和es6-promise这样的polyfill做替代,在
system.js
之前加载。
后记
自此,我们学习到了Babel的一些基础用法,包括安装和运行,以及配置和预设的用法,同时也初探了一些编译后的文件的运行问题。但是要用好Babel,还有很多问题需要继续探讨,期待我的下一篇笔记。
参考
https://babeljs.io/
https://github.com/thejamesky...
https://github.com/systemjs/s...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。