曾经,有一个 gulp-browserify 摆在我面前,后来它被加入了黑名单。
按照 CommonJS 规范开发浏览器端应用越来越流行,这过程中 Browserify 功不可没。而 gulp 作为当下最流行的 JavaScript 构建工具,browserify 免不了要它发生关系 :stuck_out_tongue:。
社区为 gulp 开发了各种各样的插件,但 gulp 生态系统是有逼格的,不是来者不拒。对于一些不符合 gulp 理念的插件,被毫不留情地加入了黑名单,gulp-browserify 便是其中之一。
gulp-browserify 对新手来说还是挺方便,现在每周还有近 5k 的下载量。如果你喜欢,还是可以继续使用,只是不再有人维护和更新。
本文要说的,正是离开 gulp-browserify 这个中间人后,如何在 gulp 中使用 browserify。其实在上一篇文章中,已经详细解释了背后的原理,本文只是对使用例子做进一步整理。
要点:Stream 转换
vinyl-source-stream + vinyl-buffer
- vinyl-source-stream: 将常规流转换为包含 Stream 的 vinyl 对象;
- vinyl-buffer: 将 vinyl 对象内容中的 Stream 转换为 Buffer。
var browserify = require('browserify');
var gulp = require('gulp');
var uglify = require('gulp-uglify');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
gulp.task('browserify', function() {
return browserify('./src/js/app.js')
.bundle()
.pipe(source('bundle.js')) // gives streaming vinyl file object
.pipe(buffer()) // <----- convert from streaming to buffered vinyl file object
.pipe(uglify()) // now gulp-uglify works
.pipe(gulp.dest('./dist/js'));
});
其中,vinyl-buffer
这一步可以使用 gulp-stream 或者 gulp-streamify 替代,解决插件不支持 stream 的问题。
var browserify = require('browserify');
var gulp = require('gulp');
var uglify = require('gulp-uglify');
var source = require('vinyl-source-stream');
var streamify = require('gulp-streamify');
gulp.task('browserify', function() {
return browserify('./src/js/app.js')
.bundle()
.pipe(source('bundle.js')) // gives streaming vinyl file object
.pipe(buffer())
.pipe(streamify(uglify())) // let gulp-uglify work with stream
.pipe(gulp.dest('./dist/js'));
});
through2
在 gulp 管道中使用 throuth2 操作 vinyl 文件对象,browserify 处理以后再返回管道中。
var browserify = require('browserify');
var gulp = require('gulp');
var uglify = require('gulp-uglify');
var through2 = require('through2');
gulp.task('browserify', function() {
return gulp.src('./src/js/app.js')
.pipe(through2.obj(function(file, enc, next) {
browserify(file.path)
// .transform(reactify)
.bundle(function(err, res) {
err && console.log(err.stack);
file.contents = res;
next(null, file);
});
}))
.pipe(uglify()) // uglify
.pipe(gulp.dest('./dist/js'));
});
这其实和使用 vinyl-transform 是一个原理,只是从 browserify 9.x
某个版本开始,下面的代码不再工作,原因未知,因此不建议使用。
var gulp = require('gulp');
var browserify = require('browserify');
var transform = require('vinyl-transform');
var uglify = require('gulp-uglify');
gulp.task('browserify', function () {
var browserified = transform(function(filename) {
var b = browserify(filename);
return b.bundle();
});
return gulp.src(['./src/app.js'])
.pipe(browserified)
.pipe(uglify())
.pipe(gulp.dest('./dist'));
});
其他任务
把常规流转转成 vinyl 对象流是在 gulp 中直接使用 browserify 的关键点,**理解了这点,所有问题都迎刃而解了,其他操作也是在此基础上进行的。
多文件操作
有时我们需要把多个文件添加到 browserify 中,可以借助 node-glob 这个模块实现:
var gulp = require('gulp');
var browserify = require('browserify');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var glob = require('node-glob');
var uglify = require('gulp-uglify');
gulp.task('browserify', function(cb) {
glob('./src/**/*.js', {}, function(err, files) {
var b = browserify();
files.forEach(function(file) {
b.add(file);
});
b.bundle()
.pipe(source('output.js'))
.pipe(buffer())
.pipe(uglify())
.pipe(gulp.dest('./dist'));
cb();
});
});
当然,也可以继续使用 gulp.src('./src/**/*.js')
,然后使用 through2 处理。
使用 Watchify 提高速度
当依赖的文件很多时,browserify 处理速度会很慢,使用 watchify 可以大幅提高处理速度。
var watchify = require('watchify');
var browserify = require('browserify');
var gulp = require('gulp');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var gutil = require('gulp-util');
var uglify = require('gulp-uglify');
// add custom browserify options here
var b = watchify(browserify(assign({}, watchify.args, {
cache: {}, // required for watchify
packageCache: {}, // required for watchify
entries: ['./src/index.js']
})));
// add transformations here
// i.e. b.transform(coffeeify);
gulp.task('browserify', bundle);
b.on('update', bundle); // on any dep update, runs the bundler
b.on('log', gutil.log); // output build logs to terminal
function bundle() {
return b.bundle()
// log errors if they happen
.on('error', gutil.log.bind(gutil, 'Browserify Error'))
.pipe(source('bundle.js'))
// optional, remove if you don't need to buffer file contents
.pipe(buffer())
.pipe(uglify())
.pipe(gulp.dest('./dist'));
}