软件环境
由于相关软件和模块正处于高速发展期,无法保证你阅读这篇文章的时候还能照着一步一步准确无误地运行下去,以下列出在编写本文时所用到的软件和模块的版本:
- Node.js
v5.1.0
- npm
3.3.12
- babel
6.2.0 (babel-core 6.2.1)
- mocha
2.3.4
配置babel编译环境
1、安装babel
Babel is a JavaScript compiler. Use next generation JavaScript, today
目前最新版的Node.js(v5.1.0)还未完全支持ES2015的新语法特性,而且我们编写的模块可能要在Node v0.12.x或更低版本下运行,因此需要借助babel将ES2015标准的JavaScript程序转换成ES5标准的。
执行以下命令安装babel:
$ npm i -g babel-cli
由于babel依赖的模块比较多,可能会花费比较长的时间甚至安装不成功,可以尝试使用cnpmjs的NPM镜像,比如(简单在安装命令末尾添加--registry=http://registry.npm.taobao.org
):
$ npm i -g babel-cli --registry=http://registry.npm.taobao.org
cnpmjs镜像的详细介绍可访问其官网:http://cnpmjs.org/
安装完成后,系统将获得以下两个命令:
babel
编译器babel-node
可以直接运行ES2015程序的Node命令
babel-cli
的详细用法可以参考其文档:https://babeljs.io/docs/usage/cli/
2、初始化项目
执行以下命令初始化项目(执行npm init
时需要按提示输入相应信息,可直接按回车跳过):
$ mkdir es2015_demo && cd es2015_demo && git init && npm init
现在我们新建一个文件test.js
试试是否能正常运行:
function sleep(ms = 0) {
return new Promise((resolve, reject) => setTimeout(resolve, ms));
}
async function test() {
for (let i = 0; i < 10; i++) {
await sleep(500);
console.log(`i=${i}`);
}
}
test().then(() => console.log('done'));
执行以下命令运行test.js
:
$ babel-node test.js
在我本机的环境下显示以下错误信息:
/usr/local/lib/node_modules/babel-cli/node_modules/babel-core/lib/transformation/file/index.js:540
throw err;
^
SyntaxError: /private/tmp/es2015_demo/test.js: Unexpected token (5:6)
3 | }
4 |
> 5 | async function test() {
| ^
6 | for (let i = 0; i < 10; i++) {
7 | await sleep(500);
8 | console.log(`i=${i}`);
...
由提示信息可判断出,应该是不支持async function
导致的,因为这是ES7标准中定义的新语法,需要配置相应的babel插件才能支持它。本文为了方面使用最新的JavaScript语法,暂时不考虑babel的编译性能,直接开启所有可能用到的插件,具体可以自行研究babel的官方文档。
新建文件.babelrc
:
{
"presets": ["es2015", "stage-0"]
}
.babelrc
为babel的配置文件,保存在项目的根目录下,其中presets
用于设置开启的语法特性集合,详细介绍可参考官方文档:https://babeljs.io/docs/usage/babelrc/ 和 http://babeljs.io/docs/plugins/#presets
接下来我们还需要安装插件依赖的模块,执行以下命令安装并保存到package.json
的devDependencies
中:
$ npm i babel-preset-es2015 babel-preset-stage-0 --save-dev
现在再重新执行test.js
,可看到控制台每隔500ms打印出一行,直到输出done
时结束:
$ babel-node test.js
i=0
i=1
i=2
i=3
i=4
i=5
i=6
i=7
i=8
i=9
done
3、编译程序
在发布项目时,要求可以在不依赖babel编译器的环境下运行,因此我们需要将ES2015的程序编译成ES5的:
$ babel test.js --out-file test.compiled.js
执行上面的命令后,生成了编译后的文件test.compiled.js
,我们尝试执行它看看:
$ node test.compiled.js
在我的系统环境下提示以下出错信息:
/private/tmp/es2015_demo/test.compiled.js:4
var ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee() {
^
ReferenceError: regeneratorRuntime is not defined
at /private/tmp/es2015_demo/test.compiled.js:4:31
...
经阅读官方文档可知,编译后的JavaScript程序有时候需要依赖一些运行时polyfill
,通过安装babel-polyfill
模块来获得:
$ npm i babel-polyfill --save
然后,我们需要修改编译后的文件test.compiled.js
,在其首行加上以下代码来载入babel-polyfill
:
require('babel-polyfill');
再次执行test.compiled.js
便可看到与$ babel-node test.js
一样的结果。
polyfill
的详细介绍可参考官方文档:http://babeljs.io/docs/usage/polyfill/
至此,我们已经配置了一个能使用ES2015语法的Node.js运行环境了。
4、重要提示
在一个Node.js进程中只能载入一个版本的babel-polyfill
,不同的模块所require('babel-polyfill')
很可能不是同一个版本,此时进程会抛出一个异常并退出,所以一般建议在打包的NPM模块中不要有require('babel-polyfill')
,而是要求在使用该模块的最终项目自行编写require('babel-polyfill')
,这样可以保证一个进程中只会有一个babel-polyfill
版本。