Babel 入门教程

作者: 阮一峰

日期: 2016年1月25日

珠峰培训

(说明:本文选自我的新书《ES6 标准入门(第二版)》的第一章《ECMAScript 6简介》

Babel是一个广泛使用的转码器,可以将ES6代码转为ES5代码,从而在现有环境执行。

这意味着,你可以现在就用 ES6 编写程序,而不用担心现有环境是否支持。下面是一个例子。


// 转码前
input.map(item => item + 1);

// 转码后
input.map(function (item) {
  return item + 1;
});

上面的原始代码用了箭头函数,这个特性还没有得到广泛支持,Babel将其转为普通函数,就能在现有的JavaScript环境执行了。

一、配置文件.babelrc

Babel的配置文件是.babelrc,存放在项目的根目录下。使用Babel的第一步,就是配置这个文件。

该文件用来设置转码规则和插件,基本格式如下。


{
  "presets": [],
  "plugins": []
}

presets字段设定转码规则,官方提供以下的规则集,你可以根据需要安装。


# ES2015转码规则
$ npm install --save-dev babel-preset-es2015

# react转码规则
$ npm install --save-dev babel-preset-react

# ES7不同阶段语法提案的转码规则(共有4个阶段),选装一个
$ npm install --save-dev babel-preset-stage-0
$ npm install --save-dev babel-preset-stage-1
$ npm install --save-dev babel-preset-stage-2
$ npm install --save-dev babel-preset-stage-3

然后,将这些规则加入.babelrc


  {
    "presets": [
      "es2015",
      "react",
      "stage-2"
    ],
    "plugins": []
  }

注意,以下所有Babel工具和模块的使用,都必须先写好.babelrc

二、命令行转码babel-cli

Babel提供babel-cli工具,用于命令行转码。

它的安装命令如下。


$ npm install --global babel-cli

基本用法如下。


# 转码结果输出到标准输出
$ babel example.js

# 转码结果写入一个文件
# --out-file 或 -o 参数指定输出文件
$ babel example.js --out-file compiled.js
# 或者
$ babel example.js -o compiled.js

# 整个目录转码
# --out-dir 或 -d 参数指定输出目录
$ babel src --out-dir lib
# 或者
$ babel src -d lib

# -s 参数生成source map文件
$ babel src -d lib -s

上面代码是在全局环境下,进行Babel转码。这意味着,如果项目要运行,全局环境必须有Babel,也就是说项目产生了对环境的依赖。另一方面,这样做也无法支持不同项目使用不同版本的Babel。

一个解决办法是将babel-cli安装在项目之中。


# 安装
$ npm install --save-dev babel-cli

然后,改写package.json


{
  // ...
  "devDependencies": {
    "babel-cli": "^6.0.0"
  },
  "scripts": {
    "build": "babel src -d lib"
  },
}

转码的时候,就执行下面的命令。


$ npm run build

三、babel-node

babel-cli工具自带一个babel-node命令,提供一个支持ES6的REPL环境。它支持Node的REPL环境的所有功能,而且可以直接运行ES6代码。

它不用单独安装,而是随babel-cli一起安装。然后,执行babel-node就进入PEPL环境。


$ babel-node
> (x => x * 2)(1)
2

babel-node命令可以直接运行ES6脚本。将上面的代码放入脚本文件es6.js,然后直接运行。


$ babel-node es6.js
2

babel-node也可以安装在项目中。


$ npm install --save-dev babel-cli

然后,改写package.json


{
  "scripts": {
    "script-name": "babel-node script.js"
  }
}

上面代码中,使用babel-node替代node,这样script.js本身就不用做任何转码处理。

四、babel-register

babel-register模块改写require命令,为它加上一个钩子。此后,每当使用require加载.js.jsx.es.es6后缀名的文件,就会先用Babel进行转码。


$ npm install --save-dev babel-register

使用时,必须首先加载babel-register


require("babel-register");
require("./index.js");

然后,就不需要手动对index.js转码了。

需要注意的是,babel-register只会对require命令加载的文件转码,而不会对当前文件转码。另外,由于它是实时转码,所以只适合在开发环境使用。

五、babel-core

如果某些代码需要调用Babel的API进行转码,就要使用babel-core模块。

安装命令如下。


$ npm install babel-core --save

然后,在项目中就可以调用babel-core


var babel = require('babel-core');

// 字符串转码
babel.transform('code();', options);
// => { code, map, ast }

// 文件转码(异步)
babel.transformFile('filename.js', options, function(err, result) {
  result; // => { code, map, ast }
});

// 文件转码(同步)
babel.transformFileSync('filename.js', options);
// => { code, map, ast }

// Babel AST转码
babel.transformFromAst(ast, code, options);
// => { code, map, ast }

配置对象options,可以参看官方文档http://babeljs.io/docs/usage/options/

下面是一个例子。


var es6Code = 'let x = n => n + 1';
var es5Code = require('babel-core')
  .transform(es6Code, {
    presets: ['es2015']
  })
  .code;
// '"use strict";\n\nvar x = function x(n) {\n  return n + 1;\n};'

上面代码中,transform方法的第一个参数是一个字符串,表示需要转换的ES6代码,第二个参数是转换的配置对象。

六、babel-polyfill

Babel默认只转换新的JavaScript句法(syntax),而不转换新的API,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码。

举例来说,ES6在Array对象上新增了Array.from方法。Babel就不会转码这个方法。如果想让这个方法运行,必须使用babel-polyfill,为当前环境提供一个垫片。

安装命令如下。


$ npm install --save babel-polyfill

然后,在脚本头部,加入如下一行代码。


import 'babel-polyfill';
// 或者
require('babel-polyfill');

Babel默认不转码的API非常多,详细清单可以查看babel-plugin-transform-runtime模块的definitions.js文件。

七、浏览器环境

Babel也可以用于浏览器环境。但是,从Babel 6.0开始,不再直接提供浏览器版本,而是要用构建工具构建出来。如果你没有或不想使用构建工具,可以通过安装5.x版本的babel-core模块获取。


$ npm install babel-core@old

运行上面的命令以后,就可以在当前目录的node_modules/babel-core/子目录里面,找到babel的浏览器版本browser.js(未精简)和browser.min.js(已精简)。

然后,将下面的代码插入网页。


<script src="node_modules/babel-core/browser.js"></script>
<script type="text/babel">
// Your ES6 code
</script>

上面代码中,browser.js是Babel提供的转换器脚本,可以在浏览器运行。用户的ES6脚本放在script标签之中,但是要注明type="text/babel"

另一种方法是使用babel-standalone模块提供的浏览器版本,将其插入网页。


<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.4.4/babel.min.js"></script>
<script type="text/babel">
// Your ES6 code
</script>

注意,网页中实时将ES6代码转为ES5,对性能会有影响。生产环境需要加载已经转码完成的脚本。

下面是如何将代码打包成浏览器可以使用的脚本,以Babel配合Browserify为例。首先,安装babelify模块。


$ npm install --save-dev babelify babel-preset-es2015

然后,再用命令行转换ES6脚本。


$  browserify script.js -o bundle.js \
  -t [ babelify --presets [ es2015 react ] ]

上面代码将ES6脚本script.js,转为bundle.js,浏览器直接加载后者就可以了。

package.json设置下面的代码,就不用每次命令行都输入参数了。


{
  "browserify": {
    "transform": [["babelify", { "presets": ["es2015"] }]]
  }
}

八、在线转换

Babel提供一个REPL在线编译器,可以在线将ES6代码转为ES5代码。转换后的代码,可以直接作为ES5代码插入网页运行。

九、与其他工具的配合

许多工具需要Babel进行前置转码,这里举两个例子:ESLint和Mocha。

ESLint 用于静态检查代码的语法和风格,安装命令如下。


$ npm install --save-dev eslint babel-eslint

然后,在项目根目录下,新建一个配置文件.eslint,在其中加入parser字段。


{
  "parser": "babel-eslint",
  "rules": {
    ...
  }
}

再在package.json之中,加入相应的scripts脚本。


  {
    "name": "my-module",
    "scripts": {
      "lint": "eslint my-files.js"
    },
    "devDependencies": {
      "babel-eslint": "...",
      "eslint": "..."
    }
  }

Mocha 则是一个测试框架,如果需要执行使用ES6语法的测试脚本,可以修改package.jsonscripts.test


"scripts": {
  "test": "mocha --ui qunit --compilers js:babel-core/register"
}

上面命令中,--compilers参数指定脚本的转码器,规定后缀名为js的文件,都需要使用babel-core/register先转码。

(完)

一灯学堂

优达学城

留言(51条)

通俗易懂。谢谢!

gulp-babel走起

对于 export default {} 支持不好,还得加个插件 babel-plugin-add-module-exports:
"plugins": [
"add-module-exports"
]

引用郁也风的发言:

对于 export default {} 支持不好,还得加个插件 babel-plugin-add-module-exports:
"plugins": [
"add-module-exports"
]

早看到这条评论就好了

很清晰,很有帮助。刚好这几天在折腾babel6。支持一下~

能否讲解一下配置文件.babelrc,这是在Linux环境的配置文件吧,在Windows环境下如何搭建一个项目,能详细讲述么?

多谢老师指导, 拜读。

很有帮助!

Babel 的视频教程可以看这里:http://ninghao.net/course/3432

在使用babel-polyfill后,需要用bind方法绑定this的时候有所改变,this前面需要增加一个参数 如:obj.onclick(function(){console.log(this)}.bind(null, this))

学到不少

阮老师,babel-core里最后示例中es5Code和es6Code这两个变量名称是不是起反了.

@marsoln:

谢谢指出,已经改正。

babel-polyfill 包我看了看还是挺大的,生产环境如何替换啊??

引用wy的发言:

能否讲解一下配置文件.babelrc,这是在Linux环境的配置文件吧,在Windows环境下如何搭建一个项目,能详细讲述么?

.babelrc. 在后邊再加上一點

正在接触ES6语法 学习了

刚开始接触ES6语法 学习了

babel 编译import 会编译成require 还是运行不了 请教下 怎么解决

引用Ben Suen的发言:

.babelrc. 在后邊再加上一點

试了下,并不行

想问一下.bablrc是文件名还是扩展名,如果是扩展名,那么文件名是什么,好怪的写法。

babel5升级babel6带来的export default问题真是烦

谢谢您通俗易懂的小教程。

没有网络的环境下离线怎么安装babel

如果我在babelrc中加入了 `babel-plugin-transform-runtime` 可以不选择 `babel-polyfill` 吗?
相关配置如下:
{
"presets": ["latest", "react", "stage-0"],
"plugins": ["transform-runtime"]
}

引用leo的发言:

如果我在babelrc中加入了 `babel-plugin-transform-runtime` 可以不选择 `babel-polyfill` 吗?
相关配置如下:
{
"presets": ["latest", "react", "stage-0"],
"plugins": ["transform-runtime"]
}

babel-polyfill 与 babel-runtime 是两个概念

babel-polyfill 是对浏览器缺失API的支持。比如浏览器可能没有Array.from() 方法。

babel-runtime 是为了减少重复代码而生的。 babel生成的代码,可能会用到一些_extend(), classCallCheck() 之类的工具函数,默认情况下,这些工具函数的代码会包含在编译后的文件中。如果存在多个文件,那每个文件都有可能含有一份重复的代码。

babel-runtime插件能够将这些工具函数的代码转换成require语句,指向为对babel-runtime的引用,如 require('babel-runtime/helpers/classCallCheck'). 这样, classCallCheck的代码就不需要在每个文件中都存在了。

当然,最终你需要利用webpack之类的打包工具,将runtime代码打包到目标文件中。

仔细阅读了下文档, 我上面说的是有问题的。

确实,用了babel-runtime 就可以不用 babel-polyfill 了,参见官方文档:

http://babeljs.io/docs/plugins/transform-runtime/


请问阮一峰老师,在html里引入后,再用script标签引入外部脚本,浏览器就会报错跨域,这是怎么回事?

挺不错的。

看了很多阮老师的文章,都讲的很细很全面,赞!

请问一下,老师,我在看您书的第2张第2.3节的const命令使用时,您书中是这样的描述的:

“const的作用域与let命令相同,只在所声明所在的块级作用域内有效”

代码:

if(true){
//console.log(MAX); // 在浏览器中测试时,与你的一致,但是在nodejs是undefined
const MAX = 5;
// console.log(MAX); // 5 在chrome浏览器下您的说法是正确的
}

console.log(MAX); // Uncaught ReferenceError: MAX is not defined,这个也证实了您的结论,只有在所在的块级作用域内有效

但是我把这段代码放在nodejs环境中,这段代码是能通过的,用babel-node 源js文件,却输出了5,正常运行,const 声明的变量只针对块级作用域有效,但这是不是矛盾了呢?不是不会变量的提升?还有const和let,在声明前调用就会报错,但是在nodejs环境中,它却是undefined,报错与undefined并不等同吧.

我猜想了一下:提出如下可能:

一:nodejs的环境原因所致,我用es-checker测了一下自己的nodejs对es6的支持程度,比书中的要高69%;您也说了,在2016会小部分的改动。

二:本身我自身的chrome浏览器配置的原因,chrome版本原因。。

网上查了一下,我并没有找到答案,还希望老师能够解下我的凝惑的,谢谢

能解释下babel-pollyfill 与babel-runtime的作用吗,不太清楚这两则是干什么用的

想问一下阮大牛。。现在用的typescript,然后ts这一套已经比较熟练了,bable是不是只需要了解下

引用farmerZ的发言:

想问一下.bablrc是文件名还是扩展名,如果是扩展名,那么文件名是什么,好怪的写法。

rc结尾的文件通常代表运行时自动加载的文件,配置等等的

我用的nodejs6最新版,.babelrc文件的内容是
{
"presets": [
["env", { "modules": false }],
"stage-2"
],
"plugins": ["transform-runtime"],
"comments": false,
"env": {
"test": {
"presets": ["env", "stage-2"],
"plugins": [ "istanbul" ]
}
}
}
通用版,
不是通常的
{"perset":["es-2015","stage-2"],
"plugins":["transfrom-runtime"],
"comments":false
}

是不是不用配置这些环境变量,直接用通用版也可以运行es6了

不吝赐教


babel-node也可以安装在项目中。

$ npm install --save-dev babel-cli

应该是想敲

$ npm install --save-dev babel-node

当js中使用了import和export时
使用babel-node xxx.js还是报错不支持import和export,有什么办法解决么。。本来装babel-cli就是因为nodejs不支持import和export,装了babel-cli还是不支持就白装了。。

引用moonlightv的发言:

当js中使用了import和export时
使用babel-node xxx.js还是报错不支持import和export,有什么办法解决么。。本来装babel-cli就是因为nodejs不支持import和export,装了babel-cli还是不支持就白装了。。

我知道可以用webpack2避免这个问题,不知道还有没有其他办法。

引用moonlightv的发言:

当js中使用了import和export时
使用babel-node xxx.js还是报错不支持import和export,有什么办法解决么。。本来装babel-cli就是因为nodejs不支持import和export,装了babel-cli还是不支持就白装了。。

引用moonlightv的发言:

当js中使用了import和export时
使用babel-node xxx.js还是报错不支持import和export,有什么办法解决么。。本来装babel-cli就是因为nodejs不支持import和export,装了babel-cli还是不支持就白装了。。

请问 你是怎么解决的 如果不用 webpack

阮哥的博绝对可以出教科书啦〜

想请问一下,安装了babel-cli但是执行babel-node的命令总是出错:
Cannot find module 'C:\Users\cjh\AppData\Roaming\npm\node_modules\.babel-cli_npminstall\node_modules\.6.18.0@babel-cli\bin\babel-node.js'
at Function.Module._resolveFilename (module.js:469:15)
at Function.Module._load (module.js:417:25)
at Module.runMain (module.js:604:10)
at run (bootstrap_node.js:393:7)
at startup (bootstrap_node.js:150:9)
at bootstrap_node.js:508:3
这是什么情况

阮老师写的文章一如既往的通俗易懂,太感谢了

.babelrc文件中
"plugins": ["transform-runtime", [
"component", [{
"libraryName": "element-ui",
"styleLibraryName": "theme-default"
}]
]],
我看同事下载完element-ui后,添加的,这是什么意思

npm install babel-core@5 为什么现在 安装不了啊! 直接

npm ERR! code E404
npm ERR! 404 Not Found: bable-core@latest

npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\Administrator\AppData\Roaming\npm-cache\_logs\2017-08-05T10_14_55_458Z-debug.log

@冷寒

刚刚发现,现在要用 npm install babel-core@old

报错Requiring external module babel-register,使用了命令 $npm install --save-dev babel-register还是不行,求教~

老师我用babel进行转码是出现这种let f = f=>a+b;var f = function f(){
return a+b;}这是为啥?为啥f多了一次

请问大神 为什么我在运行gulp时 出现了我发的错误啊
那个babel-core 还有babel-register我都安装了
还是有错误

Requiring external module babel-register

引用brookslee的发言:

仔细阅读了下文档, 我上面说的是有问题的。

确实,用了babel-runtime 就可以不用 babel-polyfill 了,参见官方文档:

http://babeljs.io/docs/plugins/transform-runtime/


Another purpose of this transformer is to create a sandboxed environment for your code. If you use babel-polyfill and the built-ins it provides such as Promise, Set and Map, those will pollute the global scope. While this might be ok for an app or a command line tool, it becomes a problem if your code is a library which you intend to publish for others to use or if you can’t exactly control the environment in which your code will run.

那里说了用runtime 就不必 polyfill了

对于新手来说。完全看不懂在说什么。配置全都跳过了。学个p

非入门者可以看懂!!!

我要发表看法

«-必填

«-必填,不公开

«-我信任你,不会填写广告链接