自動タスク実行で快適プログラミング学習
こんにちは。年度が替わりましてスマートパス開発部からインフラ部へ異動した子安です。最近すっかり暖かくなって、日本人で良かったなと思っています。
さて、近年いろいろな動画学習サービスが提供されていて楽しいですね。動画学習といえば、ブラウザで動画を見ながらエディタでコードを書いてコンソールで実行、をコツコツやるわけですが、3つのことを同時に進めていくのは大変面倒です。面倒なので書いたコードを保存したら自動的に実行されるようにしたいと考え始めました。そこで、タスクランナーとしてよく聞くGulpとかGruntとかをこの機会に試してみます。
そもそもGulpもGruntも今まで触った経験がないのですが、どっちがナウいんでしょうか。社内で聞いてみました。
え、オワコン・・・!? そうなのか・・・まあでも、実際に自分でも触ってみないとわかりませんよね。
初めに実現したいことをまとめておきます。
- 今は自分的にGoが流行ってるのでGoの動画を見て勉強するつもり
- goファイルはプロジェクト配下のsrc/ディレクトリに格納する
- コードを編集・保存したら、そのファイルに対して自動的に
go run
を実行する - 実行結果はコンソールに表示する。実行する度にコンソールをクリアする
- 環境はMac OS X(10.11.4)で、Go・Node.jsをインストール済み
Gulp
まずはロゴがかっこいいGulpから。 npmを初期化してGulpをインストールします。Gulpの設定ファイルはせっかくなのでCoffeeScriptで書きましょう。CoffeeScriptもインストールしておきます。
npm init
npm install --save-dev gulp coffee-script
ファイルの変更監視はgulp.watch
で行います。設定ファイル:gulpfile.coffeeはこんな感じになります。
# gulpfile.coffee
gulp = require 'gulp'
{spawn} = require 'child_process'
gulp.task 'watch', () ->
gulp.watch 'src/**/*.go', (event) ->
if event.type in ['added', 'changed']
console.log '\x1b[2J'
spawn 'go', ['run', event.path], {stdio: 'inherit'}
gulp.task 'default', ['watch']
これを下記のコマンドで実行します。
$(npm bin)/gulp
Grunt
次はGruntでやってみましょう。npmを初期化してGruntをインストールします。こちらも設定ファイルはCoffeeScriptで書くことにしますが、依存関係に含まれるためCoffeeScriptを個別にインストールする必要はありません。代わりにファイルの変更監視のためのプラグインが必要になります。
npm init
npm install --save-dev grunt grunt-contrib-watch
watchプラグインを設定し、イベントを捕まえてgo run
コマンドを実行するようにします。設定ファイル:Gruntfile.coffeeはこんな感じになります。
# Gruntfile.coffee
{spawn} = require 'child_process'
module.exports = (grunt) ->
grunt.initConfig
watch:
files: ['src/**/*.go']
options:
event: ['added', 'changed']
grunt.event.on 'watch', (action, filepath, target) ->
console.log '\x1b[2J'
spawn 'go', ['run', filepath], {stdio: 'inherit'}
grunt.loadNpmTasks 'grunt-contrib-watch'
grunt.registerTask 'default', ['watch']
これを下記のコマンドで実行します。
$(npm bin)/grunt
npm-scripts
最近はGulpやGruntを使わずにnpm-scriptsを使うんだという話なので、その方法も試してみたいと思います。例によってnpmを初期化して、CoffeeScriptとファイルの変更を監視してくれるchokidarというパッケージをインストールします。
npm init
npm install --save-dev coffee-script chokidar
package.json(抜粋)はこんな感じで
"scripts": {
"watch": "coffee watch.coffee"
},
呼び出すwatch.coffeeはこうなります。
# watch.coffee
chokidar = require 'chokidar'
{spawn} = require 'child_process'
chokidar.watch './src/**/*.go', ignoreInitial: true
.on 'all', (event, path) ->
if event in ['add', 'change']
console.log '\x1b[2J'
spawn 'go', ['run', path], {stdio: 'inherit'}
これを下記のコマンドで実行します。
npm run watch
まとめ
Gulp・Grunt・npm-scriptsのいずれの方法でも、実現したかったことを実現できました。
出来上がった設定ファイルを見てみると、GruntはGulpに比べて決まり文句的な記述が多く、設定を宣言的に行うようになっているため柔軟性に欠けるという印象です。Gulpとnpm-scriptsに関しては、記述内容自体にほとんど差がないですね。
それよりもそれぞれのプラグインを探すことや、Gulp・Gruntの書き方を調べることに時間がかかりました。使うために調べることが多くなってしまうのはツールとして本末転倒なので、熟れるまで使い込めるかどうかを判断する必要がありそうです。
使ったもの
- Node.js: v5.10.0
- npm: v3.8.3
- Gulp: v3.9.1
- Grunt: v1.0.0
- CoffeeScript: 1.10.0
コードはGitHubに置いています。
おまけ
というようなわけで、今回はnpmでどうやるかということを調べてきたのですが、ここまで来るともうnpmである必要もない気がしてきました。 探してみたところ、Homebrewにfswatchというコマンドがありました。
brew install fswatch
このコマンドは監視対象のファイルにイベントがあると、標準出力にファイルパス等を書き出してくれます。つまり、
fswatch -0 --include='\.go$' --exclude='.*' --event=Created --event=Updated ./src | \
while read -d '' file; do
echo $'\e[2J'
go run "${file}"
done
おやおや、一番簡単でした!これが正解だったみたいですね。
