[译]使用基于Babel的gulp

本文翻译自macr.ae

  Babel是一个JavaScript转换编译器,它可以将ES6(下一代JavaScript规范,添加了一些新的特性和语法)转换成ES5(可以在浏览器中运行的代码)。这就意味你可以在一些暂时还不支持某些ES6特性的浏览器引擎中,使用ES6的这些特性 - 比如说,class和箭头方法。本文,我将围绕gulp和babel,介绍如何使用它们。

  “使用基于Babel的gulp”其实可以有两种理解:一是使用Babel编写ES6语法的gulpfile;二是使用gulp来运行babel,让ES6编写的JavaScript代码转化成浏览器可以理解的JavaScript代码。这两种情况接下来我将一一介绍。

用ES6编写gulpfile

  Gulp自3.9版本以来,就添加了针对Babel这样的转换编译器的支持,这样你就可以使用ES6来编写gulpfile了。比如说,如果你正用着Node 0.12,你就可以使用ES6中的箭头方法了。首先,你需要使用gulp构建的项目中的npm来安装babel这个安装包。然后,你需要把gulpfile命名为gulpfile.babel.js,从而告诉gulp需要找到babel。

  在使用npm install babel-preset-es2015安装好babel-preset-es2015这个插件之后,需要在.babelrc文件内添加它(在Babel 6.0中,默认不包括任何插件):

1
2
3
{
  "presets": ["es2015"]
}

(参考the Babel website)

  此后,你就可以在gulpfile里面使用ES6的语法。举个栗子:

1
2
3
import gulp from 'gulp';

gulp.task('default', () => console.log('Default task called'));

  这些很容易理解。你可以像往常一样调用gulp,并且得到你期望的运行结果。

  如果你想指定babel的一些选项,最好的方式就是使用.babelrc。但如果这行不通的话(比如,当你想指定某个函数需要使用一个Babel选项的时候),你就不能用我上面说的方法了。所以,此时你需要创建一个名为gulpfile.js的文件,并包含如下内容:

1
2
3
4
5
require('babel/register')({
  nonStandard: process.env.ALLOW_JSX
});

require('./gulpfile.babel.js');

  然后再使用上面提到的gulpfile.babel.js。

使用Gulp构建ES6语法的文件

  只是使用babel把ES6转换为ES5是相当简单的。使用如下的gulp-babel插件:

1
2
3
4
5
6
7
8
var gulp = require('gulp');
var babel = require('gulp-babel');

gulp.task('default', function () {
    return gulp.src('src/app.js')
        .pipe(babel())
        .pipe(gulp.dest('dist'));
});

  这里的输出将会是经过babel处理的代码,它们可以用于那些暂时还不是完全支持ES6特性的浏览器中。一旦调用了gulp-babel插件,你就可以调用像uglify这样的常用插件。

  gulp-babel插件也支持gulp-sourcemaps,它可以用于简单的浏览器调试。

  这种方式下差不多唯一没有使能的特性就是ES6的模块化了。为此,我推荐使用browserify。

在基于Broswerify的gulp里调用Babel

(查询所有这些库的名字的大小写花了我一会儿工夫)

  如果你想学习ES6的模块(modules,它让你能够import工程中的其他文件),你可以结合使用Broswerify和babel。

  或许你还没有听说过Broswerify,其实它让你可以使用Node.js风格的require来编写代码:

1
2
3
var $ = require('jquery');

$('body').css('background-color', 'orange');

  Browserify支持“转换(Transforms)”,它们主要是一些高效的辅助插件 - 就像gulp里面有很多插件可以处理很多文件相关的事情一样,也有很多Browserify的转换,它们可以让你在脚本编译的机器上完成很多支持环境变量的事情,或者编译React的JSX文件。

  其中一个转换插件叫做babelify,它为Browserify添加了babel的支持。除了让你使用ES6和require()之外,它还可以把import声明转换为require(),此时你就可以在你的代码里使用ES6的模块:

1
2
3
import $ from 'jquery';

$('body').css('background-color', 'red');

  你可以在下面的代码里一起使用Browserify和babelify:

1
2
3
4
5
6
7
8
9
10
var fs = require('fs');
var babelify = require('babelify');
var browserify = require('browserify');

var bundler = browserify('src/app.js');
bundler.transform(babelify);

bundler.bundle()
    .on('error', function (err) { console.error(err); })
    .pipe(fs.createWriteStream('bundle.js'));

  bundler.bundle()方法返回了一段包含处理过的代码的可读流。我们可以使用vinyl-source-stream和vinyl-buffer,来把这个转化为可以被送入其他gulp插件和gulp.dest() 的内容:尽管之前的代码完全可以很好工作了,但最佳实践还是要避免在gulpfile里面使用fs模块。

  在gulpfile里面,之前的代码可以写成这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var babelify = require('babelify');
var browserify = require('browserify');
var buffer = require('vinyl-buffer');
var source = require('vinyl-source-stream');
var uglify = require('gulp-uglify');

gulp.task('default', function () {
    var bundler = browserify('src/app.js');
    bundler.transform(babelify);

    bundler.bundle()
        .on('error', function (err) { console.error(err); })
        .pipe(source('app.js'))
        .pipe(buffer())
        .pipe(uglify()) // Use any gulp plugins you want now
        .pipe(gulp.dest('dist'));
});

  最后,加分题!给下面的代码添加对source maps的支持。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var babelify = require('babelify');
var browserify = require('browserify');
var buffer = require('vinyl-buffer');
var source = require('vinyl-source-stream');
var sourcemaps = require('gulp-sourcemaps');
var uglify = require('gulp-uglify');

gulp.task('default', function () {
    var bundler = browserify({
        entries: 'src/app.js',
        debug: true
    });
    bundler.transform(babelify);

    bundler.bundle()
        .on('error', function (err) { console.error(err); })
        .pipe(source('app.js'))
        .pipe(buffer())
        .pipe(sourcemaps.init({ loadMaps: true }))
        .pipe(uglify()) // Use any gulp plugins you want now
        .pipe(sourcemaps.write('./'))
        .pipe(gulp.dest('dist'));
});

  棒!(它是不是有点长了,或许有必要把它拆成一个独立的文件?)


  你现在应该知道如何在你的gulpfile中使用ES6了 - 通过安装babel和重命名gulpfile为gulpfile.babel.js; 以及如何使用gulp把ES6的代码转换成ES5 - 使用gulp-babel或者结合使用babelify和Browserify。

  如果你在升级到Babel 6之后遇到了什么奇怪的error,先确认你是否使用了es2015 present