Edited at

PHPライブラリ開発のためのgulpfileとGruntfile 比較

More than 5 years have passed since last update.

ファイル変更を監視して、コマンドを実行してくれる最近のフロントエンドビルドツール。Gruntとgulpが有名どころっぽいんですが、PHPの開発にも併用して使うと楽しいです。

やりたいこととしては、以下の工程を自動化したいわけです。ローカル環境でもっと高頻度にCIを回したいという感じ。


  1. ブラウザとエディタとターミナルを準備。


    • ブラウザには http://localhost:9000/ などでカバレッジレポートを表示。

    • ターミナルでは常時PHPUnitの結果が表示される

    • エディタはもちろんソースコードとユニットテストコードを書く(何を使ってもよい)



  2. ソースコード・テストコードをエディタで書いて、保存する

  3. ファイル変更を検知して、自動でphpunitコマンドを実行

  4. PHPUnitのカバレッジレポート(HTML版)をlivereloadし、テストの足りなさそうなところを通知

昔はエディタを選んだり、環境を選んだりして結構苦労して実現していたらしいですが、今はツールをインストールしてちょちょっと設定するだけです。いい時代になったもんだ。

以下、PHPUnitやapigenなどの設定ファイルは省略しているので、こちらも見てください。

https://github.com/spindle/spindle-lib-template


Grunt

まずはGruntで実現したい場合。Gruntはこの手のツールのパイオニア的存在らしいですが、設定ファイルが煩雑になりがちで、後発のgulpの人気に押され始めているとか。

上記を実現する程度であれば、Gruntでもgulpでもさして手間は変わりません。

PHP 開発でも Grunt を使う - ngの日記

こちらをだいたいパクりました。


Gruntのインストール

他にも解説している記事が一杯あるので、適当なところで。node.jsとnpmはインストール済みであるとします。

$ npm install -g grunt-cli

$ cd path/to/php-lib-repository

$ echo '{}' > package.json
$ npm install --save-dev grunt
$ npm install --save-dev grunt-shell
$ npm install --save-dev load-grunt-tasks
$ npm install --save-dev grunt-contrib-watch
$ npm install --save-dev grunt-contrib-connect

これでpath/to/php-lib-repositoryの中ではgruntコマンドが使えるようになります。 gruntの設定ファイルを書きます。


Gruntfile.coffee


Gruntfile.coffee

#

# Gruntfile.coffee for php-library development
#
# 1. install node.js & npm
# 2. $ npm install -g grunt-cli
# 2. $ npm install
# 3. $ grunt
# 4. open http://localhost:9000/ (livereload enabled)
# 5. coding on src/* and tests/*
#
# enjoy!
# @license https://creativecommons.org/publicdomain/zero/1.0/ CC0-1.0 (No Rights Reserved.)

module.exports = (grunt) ->
grunt.initConfig
shell:
phpunit:
command: 'vendor/bin/phpunit'
options: {stdout: true, stderr: true}

apigen:
command: 'vendor/bin/apigen.php'
options: {stdout: true, stderr: true}

pdepend:
command: [
'vendor/bin/pdepend'
'--jdepend-chart=builds/pdepend.svg'
'--overview-pyramid=builds/pyramid.svg'
'--summary-xml=builds/summary.xml'
'src/'
].join ' '
options: {stdout: true, stderr: true}

connect:
server:
options:
port: 9000
base: 'builds'
livereload: true

watch:
php:
tasks: 'shell:phpunit'
files: [
'src/**/*.php'
'tests/**/*.php'
]
options:
livereload: true

require('load-grunt-tasks')(grunt)

grunt.registerTask 'default', ['connect', 'watch']
grunt.registerTask 'test', ['shell:phpunit']
grunt.registerTask 'all', ['shell']


あとはgruntと打ち込むと、ファイルの監視とlivereloadが有効になったWebサーバーが立ち上がります。

http://localhost:9000/ をブラウザで開いておき、ソースを書いていきます。PHPUnitの最近のカバレッジレポートはかなり綺麗なので、テンション上げながら作業ができます。


gulp

ぶっちゃけPHP関連のコマンドを実行する程度であれば、Gruntからgulpに乗り換えるメリットはあまりないかもしれません。設定ファイルの行数もあまり変わりませんし。


gulpのインストール

こちらもnode.jsとnpmはインストール済みであるとします。

$ npm install -g gulp

$ cd path/to/php-lib-repository

$ echo '{}' > package.json
$ npm install --save-dev gulp
$ npm install --save-dev gulp-connect


gulpfile.js

gulp testでPHPUnit実行、gulp inspectでapigenとPHP_Depend実行、gulp serverでファイル監視とサーバー立ち上げを開始です。


gulpfile.js

/**

* gulpfile.js for php-library developement
*
* 1. install node.js & npm
* 2. $ npm install
* 3. $ gulp server
* 4. open http://localhost:9000/ (livereload enabled)
* 5. coding on src/*.php and tests/*.php
*
* enjoy!
*
* @license https://creativecommons.org/publicdomain/zero/1.0/ CC0-1.0 (No Rights Reserved.)
*/

var gulp = require('gulp');
var exec = require('child_process').exec;
var connect = require('gulp-connect');

gulp.task('default', ['test', 'inspect']);

gulp.task('help', function(){
console.log('gulp test\t... kick vendor/bin/phpunit command');
console.log('gulp inspect\t... kick vendor/bin/apigen and vendor/bin/pdepend');
console.log('gulp server\t... start static web server on http://localhost:9000/');
console.log('\tcoverage report... http://localhost:9000/coverage/');
console.log('\tApiGen document... http://localhost:9000/api/');
});

gulp.task('test', function(done){
exec('vendor/bin/phpunit', function(err, stdout, stderr){
console.log(stdout);
console.error(stderr);
done();
});
});

gulp.task('inspect', function(done){
var i = 0, count = function(){ if (++i > 1) done() };
exec([
'vendor/bin/pdepend',
'--jdepend-chart=builds/pdepend.svg',
'--overview-pyramid=builds/pyramid.svg',
'--summary-xml=builds/summary.xml',
'src/'].join(' '), count);
exec('vendor/bin/apigen.php', count);
});

gulp.task('connect', ['default'], function(){
connect.server({
root: [__dirname + '/builds/'],
port: 9000,
livereload: true
});
});

gulp.task('reload', ['test'], function(){
return gulp.src('builds/coverage/**')
.pipe(connect.reload());
});

gulp.task('server', ['connect'], function(){
gulp.watch(['src/**', 'tests/**'], ['reload']);
});


カバレッジレポートの出力先であったり、watch対象のディレクトリは適宜実情に合わせて調整してください。