これからはじめるGulp #7:require-dirモジュールを使ったタスク単位のファイル分割

2014.12.07

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

前回のこれからはじめるGulp(6):gulp-plumberとgulp-notifyを使ったデスクトップ通知でgulp-plumberとgulp-notifyを使ったエラー等のデスクトップ通知を試しました。今回はタスクに含まれるパスを整理しつつrequire-dirモジュールを使ったタスク単位のファイル分割を試します。

パスの整理

まずはパスの指定を整理しておきます。必須ではありませんが、何かと便利なPathモジュールも読み込んでおきます。Pathモジュールはファイルパスを扱うユーティリティが用意されており、パスの正規化やパスの中からディレクトリ部分・ファイル名の部分だけ取得するといったメソッドが用意されている便利なモジュールです。

Pathモジュールを読み込む

Pathモジュールはnode.jsのCoreモジュールなのでインストール不要です。require()で読み込むだけですぐに利用できます。

var gulp      = require('gulp');
var path      = require('path'); //<-
var sass      = require('gulp-sass');
var connect   = require('gulp-connect');
var plumber   = require('gulp-plumber');
var notify    = require('gulp-notify');

...

パスを変数から呼び出す

gulpfile.jsで色々タスクで指定しているsrc, prodのディレクトリパスを管理するオブジェクトを作ります。

//option
var paths = {
  srcDir : 'src',
  dstDir : 'prod'
}

gulpfile.js1つで管理している場合は1カ所、後半のタスク毎にファイルを分割する場合はファイル毎に必要なパスをこれで管理します。

タスクのglobをタスクのローカル変数で管理する

glob(パスのパターン:scss/**/*.scss等)をローカル変数に定義して管理しやすくします。

gulp.task('sass', function(){
  var srcGlob = paths.srcDir + 'scss/*.scss';
  var dstGlob = paths.dstDir + 'css';
  var errorMessage = "Error: <%= error.message %>";

  gulp.src( srcGlob )
    .pipe(plumber({
      errorHandler: notify.onError( errorMessage )
    }))
    .pipe(sass())
    .pipe(gulp.dest( dstGlob ))
    .pipe(connect.reload());
});

全体を整理すると最終的にこうなります。

var gulp      = require('gulp');
var path      = require('path');
var sass      = require('gulp-sass');
var connect   = require('gulp-connect');
var plumber   = require('gulp-plumber');
var notify    = require('gulp-notify');

//option
var paths = {
  srcDir : 'src',
  dstDir : 'prod'
}

//sass
gulp.task('sass', function(){
  var srcGlob = path.join( paths.srcDir, 'scss', '*.scss' );
  var dstGlob = path.join( paths.dstDir, 'css' )
  var errorMessage = "Error: <%= error.message %>";

  gulp.src( srcGlob )
    .pipe(plumber({
      errorHandler: notify.onError( errorMessage )
    }))
    .pipe(sass())
    .pipe(gulp.dest( dstGlob ))
    .pipe(connect.reload());
});


//copy
gulp.task('copy', function(){
  var srcGlob = paths.srcDir + '/*.html';
  var dstGlob = paths.dstDir;

  gulp.src( srcGlob )
    .pipe(gulp.dest( dstGlob ))
    .pipe(connect.reload());
});


//watch
gulp.task('watch', ['sass', 'copy'], function(){
  var scssWatchGlob = paths.srcDir + 'scss/*.scss';
  var htmlWatchGlob = paths.srcDir + '/*.html';

  gulp.watch( scssWatchGlob, ['sass']);
  gulp.watch( htmlWatchGlob, ['copy']);
});


//server
gulp.task('serve', function(){
  connect.server({
    root: paths.dstDir,
    livereload: true
  });
});

//default
gulp.task('default', ['watch', 'serve']);

タスク毎にファイルを分割する

続いて本題のファイル分割です。タスク毎にファイルを分割するにはrequire-dirモジュールを使います。require-dirモジュールはディレクトリ内のjavascript, jsonファイルを自動で読み込んでくれます。オプションを有効にすると下層のディレクトリにあるファイルも再帰的に読み込めます。

require-dirのインストール

いつも通りrequire-dirを開発環境用にインストールします。

$ sudo npm install require-dir --save-dev
Password:
require-dir@0.1.0 node_modules/require-dir

require-dirの読み込み

require-dirモジュールは下記のように読み込み、ディレクトリを指定します。

var requireDir = require('require-dir');
var dir        = requireDir('./tasks');

また、下層ディレクトリにあるファイルも再帰的に呼び出したい場合はオプションのrecurse: trueを有効にします(デフォルトでは無効になっています)。

var requireDir = require('require-dir');
var dir        = requireDir('./tasks', {recurse: true});

ファイルを分ける

それではタスク毎にファイルを分けたいと思います。分ける際、タスクに使われているプラグインやモジュールの指定もそれぞれに指定しなければいけません。ここではsassタスクとcopyタスクを別ファイルにします gulpfile.jsにはdefaltタスクから直接呼び出すserveタスクとwatchタスクを残します。serveタスクを別ファイルにしてしまうとLiveReloadが効かなくなるので注意してください。

gulpfile.js

var gulp       = require('gulp');
var requireDir = require('require-dir');
var dir        = requireDir('./tasks');
var path       = require('path');
var connect    = require('gulp-connect');

//option
var paths = {
  srcDir : 'src',
  dstDir : 'prod'
}

//serve
gulp.task('serve', function(){
  connect.server({
    root: paths.dstDir,
    livereload: true
  });
});

//watch
gulp.task('watch', ['sass', 'copy'], function(){
  var scssWatchGlob = paths.srcDir + 'scss/*.scss';
  var htmlWatchGlob = paths.srcDir + '/*.html';

  gulp.watch( scssWatchGlob, ['sass']);
  gulp.watch( htmlWatchGlob, ['copy']);
});


//default task
gulp.task('default', ['watch', 'serve']);

sassタスクとcopyタスク

以下のように別ファイル化するsassタスクとcopyタスクはtasksディレクトリに保存されます。

$ tree tasks
tasks
├── copy.js
└── sass.js

sass.js

var gulp       = require('gulp');
var path       = require('path');
var sass       = require('gulp-sass');
var plumber    = require('gulp-plumber');
var notify     = require('gulp-notify');
var connect    = require('gulp-connect');

//option
var paths = {
  srcDir : 'src',
  dstDir : 'prod'
}

//task
gulp.task('sass', function(){
  var srcGlob = paths.srcDir + 'scss/*.scss';
  var dstGlob = paths.dstDir + '/css';
  var errorMessage = 'Error: <%= error.message %>';

  gulp.src( srcGlob )
    .pipe(plumber({
      errorHandler: notify.onError( errorMessage )
    }))
    .pipe(sass())
    .pipe(gulp.dest( dstGlob ))
    .pipe(connect.reload());
});

copy.js

var gulp       = require('gulp');
var connect    = require('gulp-connect');

//option
var paths = {
  srcDir : 'src',
  dstDir : 'prod'
}

//task
gulp.task('copy', function(){
  var srcGlob = paths.srcDir + '/*.html';
  var dstGlob = paths.dstDir;

  gulp.src( srcGlob )
    .pipe(gulp.dest( dstGlob ))
    .pipe(connect.reload());
});

気になかった方も多いかもしれませんが、module.exports = function(gulp) {がありません。どんな風に処理されているのかまで把握できていませんがとりあえず$ gulpで動くことが確認できました。

まとめ

タスクもファイル毎に分けることができ、パスも整理できました。Grantに比べてパフォーマンスも良く書いていて楽しいですね。明日からより複雑な処理ができるようGulpの同期処理について勉強したいと思います。

<

p class="alert">この記事はこれからはじめるGulp(7):require-dirモジュールを使ったタスク単位のファイル分割の転載です。