アカベコマイリ

HEAR NOTHING SEE NOTHING SAY NOTHING

gulp でディレクトリ構造を維持したコピー

January 05, 2015開発gulp

失敗談 & そこから得られた知見の記録。いままで gulp で複数ディレクトリの構造を維持してコピーするとき以下のようにしていた。

var gulp = require( 'gulp' );

gulp.task( 'copy', function() {
    gulp.src( 'src/*.html'  ).pipe( gulp.dest( 'dest'     ) );
    gulp.src( 'src/css/**'  ).pipe( gulp.dest( 'dest/css' ) );
    gulp.src( 'src/js/*.js' ).pipe( gulp.dest( 'dest/js'  ) );
} );

この処理だと gulp.dest が冗長なうえ同期実行のためにコールバック関数を呼び出す場合も個別に end/error イベントをハンドリングする必要があり面倒だ。それにもかかわらずこうしているのは gulp.src の対象は配列を指定可能だけど gulp.dest は単一であるため。

しかし gulp/API.md を読み直したら gulp.srcoptionsbase というプロパティがあって、これに処理対象のベースとしたいディレクトリを指定すると gulp.dest 上で構成を再現してくれるようだ。よってはじめの処理はこう書ける。

var gulp = require( 'gulp' );

gulp.task( 'copy', function() {
    return gulp.src(
        [ 'src/*.html', 'src/css/**', 'src/js/*.js' ],
        { base: 'src' }
    )
    .pipe( gulp.dest( 'dest' ) );
} );

src 以下のものを dest へ出力する際に src 時点のディレクトリ構成を維持してくれる。gulp.src のパス指定は非常に柔軟なので、これと base オプションを組み合わせれば単一の gulp.src だけで大抵は十分だろう。コピーを独立した task で定義するときもストリームが単一ならそれを返すだけで同期実行をサポートできて便利だ。

base オプションは gulp API の冒頭あたりで解説されている基本機能なのに見逃していた。はずかしい。