gulp, browserify, uglify の話 ( vinyl-source-stream と vinyl-buffer について )

gulp, browserify, uglify でトランスパイルをする場合、以下のようなタスクを書くことになります。

import browserify from 'browserify';
import gulp from 'gulp';
import source from 'vinyl-source-stream';
import buffer from 'vinyl-buffer';
import uglify from 'gulp-uglify';

gulp.task('js', () => {
  const b = browserify({
    entries: './entry.js',
  });

  return b.bundle()
    .pipe(source('app.js'))
    .pipe(buffer())
    .pipe(uglify())
    .pipe(gulp.dest('./dist/js/'));
});

ここで用いられている vinyl-source-stream と vinyl-buffer について少し調べたことをメモとして残します。

vinyl-source-stream と vinyl-buffer

GitHub - substack/node-browserify: browser-side require() the node.js way によると、browserify().bundle() はreadable streamを返すと書いてあります。

gulp は、vinyl というオブジェクトを用いるため、vinyl-source-stream で変換する必要があります。 この辺りのことは以下のページに解説があります。

umai-bow.hateblo.jp

私が気になったのは、gulp-uglify の直前に vinyl-buffer で更に変換をかけている部分です。 gulp-uglify は、gulp のプラグインであるため、vinyl-source-stream で vinyl に変換した後、直接渡してあげることが出来ないのは何故なのか疑問に思っていました。 以下のタスクのように、gulp.src() から直接 gulp-uglify に渡すことが出来るため、vinyl-buffer は無くても良いのではないかと。

import gulp from 'gulp';
import uglify from 'gulp-uglify';

gulp.task('compress', () => {
  return gulp.src('lib/*.js')
    .pipe(uglify())
    .pipe(gulp.dest('dist'));
});

vinyl-buffer が必要な理由を調べていると以下の issue を見つけました。 gulp-uglify の内部で用いている UglifyJS2 が streaming をサポートしていないと書いてあります。

github.com

vinyl/README.md at master · gulpjs/vinyl · GitHub によると、pipe() 時には file.contents が Buffer と Stream (と null) の場合で処理が変わるようです。

gulp/API.md at master · gulpjs/gulp · GitHub によると、gulp.src() は options をとり、options.bufferfalse に指定すると、file.contents が Stream になります。 そこで、以下のように gulp.src() に options を指定して gulp-uglify に渡そうとするとエラーになりました。

import gulp from 'gulp';
import uglify from 'gulp-uglify';

gulp.task('compress', () => {
  return gulp.src('lib/*.js', {buffer: false})
    .pipe(uglify())
    .pipe(gulp.dest('dist'));
});

vinyl-buffer は、GitHub - hughsk/vinyl-buffer: Convert streaming vinyl files to use buffers にある通り、Stream を Buffer に変換するため、以下のように gulp-uglify の前で pipe() してあげると、正常に動作しました。

import gulp from 'gulp';
import uglify from 'gulp-uglify';
import buffer from 'vinyl-buffer';

gulp.task('compress', () => {
  return gulp.src('lib/*.js', {buffer: false})
    .pipe(buffer())
    .pipe(uglify())
    .pipe(gulp.dest('dist'));
});

まとめ

vinyl-source-stream は、readable stream を vinyl オブジェクト (Stream) に変換し、vinyl-buffer は vinyl オブジェクトを Stream から Buffer に変換する。