2014/02/01

ビルドシステムgulpをCoffeeScriptで使ってみる

今はやりらしいgulpを使って、とりあえずソースの変換や監視などを行ってみました。

インストールと初期設定

  1. gulpをグローバルでインストール

    npm install -g gulp
    
  2. プロジェクトのdevDependenciesとしてgulpをインストール

    npm install --save-dev gulp gulp-util
    
  3. gulpfile.jsをつくる

    var gulp = require('gulp');
    var gutil = require('gulp-util');
    
    gulp.task('default', function(){
        console.log('gulp!');
    });
    

これで、実行すると次のようになります。

$ gulp
[gulp] Using file /Users/safx/src/sample/gulpfile.js
[gulp] Working directory changed to /Users/safx/src/sample
[gulp] Running 'default'...
gulp!
[gulp] Finished 'default' in 93 μs

gulpfileをCoffeeScriptで書けるようにする

gulpfileを素のJavaScriptであまり書きたくないので、いきなりですがCoffeeScriptで書けるようにします。

Using CoffeeScript for gulpfile」の2番目の方法を使います。

まず、CoffeeScriptを入れます。

npm install --save-dev coffee-script

その後は、gulpfile.jsを次のように修正します。

require('coffee-script/register');
require('./gulpfile.coffee');

そして、gulpfile.coffeeに前のgulpfile.jsと等価なコードを書きます。

gulp = require 'gulp'
gutil = require 'gulp-util'

gulp.task 'default', ->
    console.log 'gulp!'

これで、gulpすると先ほどと同じ結果が得られます。

$ gulp
[gulp] Using file /Users/safx/src/sample/gulpfile.js
[gulp] Working directory changed to /Users/safx/src/sample
[gulp] Running 'default'...
gulp!
[gulp] Finished 'default' in 80 μs

仕組みなどの詳細については次のブログのエントリで紹介されていますので、こちらを参照してください。

記述するタスクの前提

CoffeeScriptで書けるようになったので、gulpfile.coffeeに書いていきます。

なお、プロジェクト構成は次のようになっているとします。

sample
    lib/
    src/sample.ls

srcにあるLiveScriptのソースファイルsample.lsをJavaScriptに変換して、ついでにuglifyしてからlibに置く、ということをgrupfileに書いていきます。

そのために、grupfileで使うプラグインを入れておきます。

npm install --save-dev gulp-if gulp-uglify gulp-livescript gulp-coffee gulp-clean

ソースコードを変換するタスク

準備はできたので、gulpfile.coffeeに書いていきます。まず最初に、それらモジュールを読み込みます。

# misc
cond  = require 'gulp-if'
clean = require 'gulp-clean'

# compilers
uglify = require 'gulp-uglify'
lsc    = require 'gulp-livescript'
coffee = require 'gulp-coffee'

モジュールを利用して、LiveScriptを変換させます。

gulp.task 'script', ->
  gulp.src 'src/**/*.ls'
    .pipe lsc() .on 'error', gutil.log
    .pipe uglify()
    .pipe gulp.dest 'lib'

上のコードでは、gulp scriptしたときにsrc内にある全ての.lsなファイルに対して、lscでコンパイルしてから、それをuglifyしてそれをlibに入れるようになります。

$ gulp script
[gulp] Using file /Users/safx/src/sample/gulpfile.js
[gulp] Working directory changed to /Users/safx/src/sample
[gulp] Running 'script'...
[gulp] Finished 'script' in 40 ms

ファイルも変換されています。

$ cat src/sample.ls
!function foo
    console.log \hello

foo!
$ cat lib/sample.js 
(function(){function l(){console.log("hello")}l()}).call(this);

デフォルトタスクと先行タスク

コマンドラインで引数なしでgulpしたときにはdefaultが実行されます。毎回コンパイルするのにgulp scriptと入力するのも面倒なので、 デフォルトタスクを書き替えて次のようにします。

gulp.task 'default', ['script']

gulp.taskのAPIドキュメントを見れば詳細はわかりますが、 省略可能なgulp.taskの第2引数には、「このタスク実行前に実行させるタスク」を指定できます。

これで、gulpで実行したときに、scriptを実行してからdefaultを実行するようになります。

$ gulp
[gulp] Using file /Users/safx/src/sample/gulpfile.js
[gulp] Working directory changed to /Users/safx/src/sample
[gulp] Running 'script'...
[gulp] Finished 'script' in 40 ms
[gulp] Running 'default'...
[gulp] Finished 'default' in 7.38 μs

ファイルを監視するタスク

そもそも、ソースを修正する毎にgulpするのは面倒なので、ファイルを監視するようにします。

gulp.task 'watch', ->
  gulp.watch 'src/**/*.ls', ['script']

上のコードでは、ソースを監視して、変更があればタスクscriptを実行するように指定しています。

さらに、デフォルトタスクにも追加しておきます。

gulp.task 'default', ['script', 'watch']

これで、gulpで実行したときに、scriptを実行して、ついでにファイル監視も行うようになります。

$ gulp
[gulp] Using file /Users/safx/src/sample/gulpfile.js
[gulp] Working directory changed to /Users/safx/src/sample
[gulp] Running 'script'...
[gulp] Running 'watch'...
[gulp] Finished 'watch' in 5.87 ms
[gulp] Finished 'script' in 44 ms
[gulp] Running 'default'...
[gulp] Finished 'default' in 7.53 μs
[gulp] Running 'script'...
[gulp] Finished 'script' in 8.21 ms
[gulp] Running 'script'...
[gulp] Finished 'script' in 7.59 ms

変換後のソースを削除するタスク

変換後のソースを削除したいときもあるので、そのためのタスクを用意します。

gulp.task 'clean', ->
  gulp.src 'lib/*.js', {read:false}
    .pipe clean()

readはファイルの中身を読み込むかどうかのオプションです (デフォルトはtrue)。 削除するだけのファイルは読み込む意味がないのでfalseにしています。 なお、それ以外のオプションの詳細はgulp.srcのAPIドキュメントを参照してください。

コマンドライン引数を取れるようにする

uglifyなどのデバッグ時にはむしろ不要なので、必要なときにだけ行うようにします。

Pass params from CLI」を参考に次のようにします。

gulpのコマンドライン引数はgutil.envに入るので、そこから判断します。 gulp --release fooとするとgutil.env.releasefooに、gulp --releaseのように引数を省略するとtrueになるので、それを元に判定します。

isRelease = gutil.env.release?

そして、タスクscriptを書き替えます。

gulp.task 'script', ->
  gulp.src 'src/**/*.ls'
    .pipe lsc() .on 'error', gutil.log
    .pipe cond isRelease, uglify()
    .pipe gulp.dest 'lib'

cond (gulp-if)は第1引数がtrueなら第2引数を実行しますので、--releaseを指定したときのみにuglifyを行うようになりました。

$ gulp script && cat lib/sample.js 
[gulp] Using file /Users/safx/src/sample/gulpfile.js
[gulp] Working directory changed to /Users/safx/src/sample
[gulp] Running 'script'...
[gulp] Finished 'script' in 22 ms
(function(){
  function foo(){
    console.log('hello');
  }
  foo();
}).call(this);

$ gulp script --release && cat lib/sample.js
[gulp] Using file /Users/safx/src/sample/gulpfile.js
[gulp] Working directory changed to /Users/safx/src/sample
[gulp] Running 'script'...
[gulp] Finished 'script' in 37 ms
(function(){function l(){console.log("hello")}l()}).call(this);% 

おわりに

とりあえず、gulpをつかってみました。簡単なタスクならシェルスクリプトっぽく直感的に書けるのでよいです。

ソースコード (gulpfile.coffee)

# base
gulp = require 'gulp'
gutil = require 'gulp-util'

# misc
cond  = require 'gulp-if'
clean = require 'gulp-clean'

# compilers
uglify = require 'gulp-uglify'
lsc    = require 'gulp-livescript'
coffee = require 'gulp-coffee'


isRelease = gutil.env.release?


gulp.task 'script', ->
  gulp.src 'src/**/*.ls'
    .pipe lsc() .on 'error', gutil.log
    .pipe cond isRelease, uglify()
    .pipe gulp.dest 'lib'


gulp.task 'watch', ->
  gulp.watch 'src/**/*.ls', ['script']


gulp.task 'clean', ->
  gulp.src 'lib/*.js', {read:false}
    .pipe clean()


gulp.task 'default', ['script', 'watch']

関連リンク

0 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。