LoginSignup
149
148

More than 5 years have passed since last update.

gulpfile スタイルガイド - v0.5.0

Last updated at Posted at 2014-09-09

このドキュメントは、gulpfileの再利用性/メンテナンス性を高めることを目的とした、非公式なスタイルガイドです。

更新情報
  • 2014/10/05 - バージョン番号つけました。
  • 2014/10/04 - 「タスク辞書」あらため「タスクの共有」に。以前の内容はgulpfilesとして別ドキュメントに。

はじめに

gulpfilegulp.jsのタスクを定義するファイルです。スクリプトファイルなので自由に書ける反面、プロジェクトが大きくなると、書式を統一が問題になります。そんな時、このスタイルガイドが役に立つでしょう。対象となるのは次のようなケースです。

  • gulp.js に慣れて来て、再利用性のあるタスクを書きたい
  • チームで運用する必要があり、書式を統一したい

スタイルガイドとして、下記を参考にしています。また、ここで述べない JavaScript / CoffeeScript の言語としての記述スタイルについても、こちらを参照してください。

チェックリスト

スタイルガイドに全て目を通す前に、簡単に診断できるチェックリストを挙げておきます。後半への見出しも兼ねます。

項目 チェックすること
a.レイアウト インデントあたりスペース2つ、1行あたり最大79字、UTF-8
b.記述言語 JavaScript か CoffeeScript
c.プラグイン ブラックリスト入りはNG、インラインプラグインは適宜
d.繰り返し ファイルならgulp-foreach、配列ならmerge-stream
e.非同期処理 関数がプロミスを返す場合はプロミス、それ以外はコールバック
f.設定ファイル package.jsonにカスタムフィールド、多い場合は別ファイル
g.ファイル分割 1ファイルあたり50行程度まで、それ以上は目的別に分割
タスク名はファイル名を接頭辞にしてハイフン区切り
タスクファイルはtask/またはtasks/ディレクトリに配置
require-dirで読み込み

コードレイアウト

タブかスペースか

スペースのみを使います。1インデントあたり、2スペースとします。タブとスペースを混ぜてはいけません。

1ラインの最大文字数

すべての行は、最大79文字までに制限します。モニターがどんなに大きくても、これを越えてはいけません。

エンコーディング

UTF-8です。

モジュールの読み込み

順序変更 / コピー&ペーストしやすいように、一行ずつvarを使います。

var gulp       = require('gulp');
var browserify = require('browserify');
var source     = require('vinyl-source-stream');

以下は「悪い」例です。同じこと(モジュールの読み込み)をしているにも関わらず、行ごとの表記がことなるのは望ましくありません。JavaScriptの省略記法は、初学者を混乱させるので避けます。

var gulp       = require('gulp')
   ,browserify = require('browserify')
   ,source     = require('vinyl-source-stream');

記述言語

gulpfileは、下記のいずれかで記述します。

  • JavaScript
  • CoffeeScript

JavaScriptが「共通言語」

外部に公開する場合、プレゼンテーションで表示する場合は、JavaScriptを基本とします。また、フォーラムなどへの質問に際してもCoffeeScriptを主題としない限り、JavaScriptで投稿するべきです。

CoffeeScript

共通言語としてJavaScriptが推奨されながら、CoffeeScriptを使う理由は、「設定ファイル」としての見やすさです。gulpfileの記述にあたっての利点を下記に列挙します。

  • 括弧の省略
  • カンマの省略
  • 文字列挿入 (String Interpolation)

その他のAltJS言語

gulpfileは、その他のLiveScript他の言語で記述することも可能ですが、これはチームメンバーで合意が出来ている場合に限定されます。将来参加するメンバーについても想定に入れておくべきでしょう。

プラグインについて

ブラックリスト入りしているプラグインを避ける

プラグインは、公式ディレクトリで検索可能です。ただし、ブラックリストに入っていると表示されません。実際に使用する前に、ここで確認しておきましょう。gulp.jsのバージョン4以降は下記のコマンドでもチェックが可能になります。

$ gulp --verify

どうしても「ブラックリスト入り」を利用する必要がある場合は、その旨をgulpfileにコメントとして明記します。

インラインプラグイン

gulpfile内で、関数としてその場だけで使う「インラインプラグイン」を実装するケースがあります。

  • 再利用性が低い
  • プラグインが公開されていない
  • JavaScript APIを使う必要がある

などの場合です。下記はDuoを使う一例ですが、別関数とすることでタスク内の見通しが良くなっています。

gulp.task('script', function() {
  gulp.src('main.js')
    .pipe(duo())
    .pipe(gulp.dest('dist'))
})

function duo() {
  return map(function(file, cb) {
    Duo(file.base)
      .src(file.contents.toString());
      .run(function(err, src) {
        if (err) return cb(err);
        file.contents = new Buffer(src);
        cb(null, file);
      });
  });
}

スクリプト

繰り返し(1)

ファイルについての繰り返しには、gulp-foreachを使います。

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

gulp.task('zip', function(){
  return gulp.src('recipe/*')
    .pipe(foreach(function(stream, file){
      return gulp.src(
           path.basename(file.path) + '/**/*',
           { cwd: 'recipe/' }
        )
        .pipe(zip(name + '.zip'));
    }))
    .pipe(gulp.dest('download/'));
});

繰り返し(2)

配列内の繰り返しについては、merge-streamを使います。

var merge = require('merge-stream');

var data = [{ name: 'a' }, { name: 'b' }, { name: 'c' }];

gulp.task('page', function(){
  return merge(data.map(function(entry){
    return gulp.src('template.html')
      .pipe(consolidate(entry))
      .pipe(gulp.dest('dist/'));
  }));
});

※CoffeeScriptの場合は、for文の方が読みやすいでしょう。

プロミス (promise)

タスク内で非同期関数が使われる場合で、関数がプロミス(promise)を返す場合は、関数の結果をタスク内でreturnします。コールバックと、プロミスの両方に対応する関数の場合、プロミスを使うことを優先します。

gulp.task('async', function(){
  return iHaveAPromise();
});

独自のプロミス

タスク内で独自のプロミスを生成することは、可読性を下げます。特にチーム内のデザイナーにとって、次のようなコードは理解しにくいものとなります。次項のコールバックを使う方が望ましいでしょう。

gulp.task('async', function(){
  var deferred = Q.defer();

  setTimeout(function() {
    deferred.resolve();
  }, 1000);

  return deferred.promise;
});

そんなとき「then」

プロミスはthenを使って次の処理につなげられる点が便利ですが、タスク内での利用は必ずしも推奨されません。thenでタスク内の処理を長々と書くよりも、

  • タスクは十分に小さいか (特定の目的にフォーカスしているか)
  • タスクの外側でコントロールすべきではないか

を確認すべきです。連続するタスクをコントロールするために、次の方法が用意されています。

  • gulp.js v3.x: run-sequenceが利用可能です。
  • gulp.js v4.x: 標準APIに、gulp.parallelgulp.seriesが追加されました。

コールバック

タスク内で非同期関数が使われる場合で、プロミスに対応していない場合、引数としてコールバック関数を受け取り、非同期処理が完了時点でコールバック関数を呼び出します。コールバック関数であることを明示するため、callbackないしcbを一貫して使うものとします。

gulp.task('async', function(callback){
  setTimeout(function() {
    callback();
  }, 1000);
});

設定ファイル

gulpfileを複数プロジェクトで共有して、固有の値だけを変更したい場合があります。その場合は、package.jsonにカスタムフィールドを追加して記述します。設定の数が大量にある場合は、config.jsonといった名称で別ファイルに記述することが望ましいでしょう。

下記は、パッケージ名をフォントの名称にしている例です。

var meta = require('./package.json');

gulp.task('icon', function(){
  gulp.src('icon/*.svg')
    .pipe(iconfont({ fontName: meta.name })
    .pipe(gulp.dest('dist'));
});

ファイルの分割

通常のスクリプトと同様に、長過ぎるgulpfileはメンテナンス性が下がります。目的別に分割する必要があります。

gulpfileは1ファイルあたり、50行程度に留めるべきです。何行以下という制限は特に設けませんが、ひとつのファイルには、ひとつの目的のタスクのみを集約します。例えば、JavaScriptを扱うタスクと、CSSを扱うタスクは別のファイルにするべきです。

プロジェクトが大きくなると、担当者ごとに管理するgulp.jsのタスクが分かれて行きます。その際、他のメンバーが担当するタスクを不用意に変更する必要がないよう、タスクのモジュール性を維持するのは、良い戦略です。

以下、便宜的に次のように呼ぶこととします。

  • ルートファイル(root file): プロジェクトディレクトリ直下のgulpfile
  • タスクファイル(task file): タスクや目的別に分けられたgulpfile

タスクの再利用性

プロジェクトごとにタスクの組み合わせや設定が変わっても、タスクファイルはプロジェクト間で流用可能なケースが多々あります。下記の方針を立てることは、再利用性を高めるために重要です。

  • 目的ごとにタスクファイルを分ける
  • タスクファイル外のタスクに依存しない
  • シンプルに留める

1タスクごとに1タスクファイルとする必要はありません。例えばタスクファイルcoffee.jsに、

  • coffee
  • coffee-client
  • coffee-server
  • coffee-lint

といった複数のタスクを定義して構いません。これらのタスクは、必要とするモジュールも、利用されるシーンも重なっており、1ファイルにまとめるのが合理的です。

ルートファイルに含めるべきタスク

プロジェクト間で共有しにくいタスクがあります。次の3つについては、ルートファイルに含めます。

  • default
  • clean
  • watch

また、以下のケースも、ルートファイルに書くと良いでしょう。

  • 横断的に実行すべきタスク (他のgulpfileに依存するタスク)
  • アドホックなタスク

タスクファイルの置き場所

プロジェクトのルートにgulpfileが散乱するのは、望ましくありません。taskないし、tasksディレクトリにまとめます。下記は配置の例です。

  • gulpfile.js (ルートファイル)
  • task/
    • bower.js (タスクファイル)
    • css.js (タスクファイル)
    • coffee.js (タスクファイル)
    • icon.js (タスクファイル)

タスクファイルの読み込み

タスクファイルを読み込むには、require-dirモジュールを利用します。ルートファイルの先頭に下記を追加します。

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

タスク名は、ファイルを越えてgulp.jsのプロセス内で共有されます。そのため、この記述だけで、他のファイルに書かれたタスク('css'とか'script'とか)を呼び出すことが出来るようになります。

タスクファイルの記述

タスクファイルも、通常のgulpfileと同様に記述します。module.exports = yourFunctionの形式で書く必要はありません。

タスク名は、ファイル名と同一か、ファイル名を接頭辞とします。

対象
ファイル名 coffee.js
タスク名 coffee, coffee-client, coffee-serverなど

タスクファイルの共有

再利用を促進するには、タスクファイルをGitHubに置くのが有効です。(Dotfilesを思い出してください)

149
148
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
149
148