Panda Noir

JavaScript の限界を究めるブログでした。最近は幅広めに書いてます。

gulpでJSの圧縮+モジュールバンドルをする

GulpっぽくRollupする記事が日本語で見つからなかったので書きました。

やりたいこと

Rollupと圧縮を同時にやるために.pipeで2つをつなぎたい

必要なもの

  • rollup-stream
  • vinyl-source-stream
  • vinyl-buffer

rollup-streamは、「gulpがStreamを受け取って処理するのに、RollupがPromiseを返す仕様だから、PromiseをStreamへラップする必要がある」ために使うようです。

vinyl-source-streamやvinyl-bufferの役割についてはあまりよくわかっていません。なんか必要らしいです。

原理についてはわかっていなくてもとりあえず動けばおけまるなので、gulpfileを書いていきます。

設定

まず必要なものをインストールします。

$ yarn add -D gulp google-closure-compiler vinyl-source-stream vinyl-buffer gulp rollup-stream

もしくは

$ npm i -D gulp google-closure-compiler vinyl-source-stream vinyl-buffer gulp rollup-stream

次にそれらを読み込んでいきます。

// gulpfile.js
const closureCompiler = require('google-closure-compiler').gulp();
const source = require('vinyl-source-stream');
const buffer = require('vinyl-buffer');

const gulp = require('gulp');

const rollup = require('rollup-stream');

Closure Compilerはgoogle-closure-compilerをインストールしてください。gulp-closure-compilerはGitHubのリポジトリが消失済みな上に、Closure Compilerのバージョンが2年以上前のものなので使い物になりません。

いよいよタスクを書いていきます。

// 続き
gulp.task('js', () => {
    return rollup({
        input: 'js/main.js',
        format: 'iife'
    }) // gulp.src().pipe(rollup)ではなく、rollup()
    .pipe(source('main.js', 'js/')) // ファイル名、フォルダの順
    .pipe(buffer()) // これをかませないとエラーが出る
    // 以降はgulpの記法がそのまま使える
    .pipe(closureCompiler({
        compilation_level: 'SIMPLE',
        language_in: 'ECMASCRIPT6_STRICT',
        language_out: 'ECMASCRIPT5_STRICT',
        js_output_file: 'main.min.js'
    })) // 普通にかませられる
    .pipe(gulp.dest('./dist'));
});

こんな感じとなります。ポイントは、source()buffer()をかませている点です。この2つをかませたら、それ以降は普通のgulpと同じように書けます。Closure Compiler以外の処理もかませることができます。

おまけ: 複数ファイルを並列処理する

上の設定ではjs/main.jsという1つのファイルしか処理できませんので、複数ファイルを処理するやり方も書きます。

まず、event-streamを追加します。

$ yarn add -D event-stream
$ npm i -D event-stream

次にevent-streamを読み込みます。

// gulpfile.js
const merge = require('event-stream').merge;

あとは先程の処理を関数化してmerge()でまとめてやれば完成です。

gulp.task('js', () => {
    const compile = input => {
        return rollup({
            input: `js/${input}`,
            format: 'iife'
        })
        .pipe(source(input, 'js/'))
        .pipe(buffer())
        .pipe(closureCompiler({
            compilation_level: 'SIMPLE',
            language_in: 'ECMASCRIPT6_STRICT',
            language_out: 'ECMASCRIPT5_STRICT',
            js_output_file: input.replace('.js', '.min.js')
        }))
        .pipe(gulp.dest('./js'));
    };
    return merge(
        compile('main.js'),
        compile('article.js'),
        compile('contact.js')
    );
});