オレ的Gruntに対する最新の気持ち

Gruntについて最新の気持ち ::ハブろぐ

上記のブログエントリを読んで非常に今自分が感じていることと共通点を感じました。

Gruntに対する最新の気持ちでは2つの問題提起がされてました。

1. Gruntfile.jsが長すぎる(700行とか)
2. そもそも全部gruntでやらなきゃいけないのか

1.に関しては色んな解決手段があります、ブログの筆者も解決されているようですし、この件に関しては次回のMaintainable Gruntfile.jsで触れます。

最初は2.に関しての、全部gruntでやらなきゃいけないんだっけ、という疑問に関してです。

僕も同じ思いをしてたので、同調してブログを書きます。

gruntについて

言わずと知れたタスクランナーですね、gruntを使うとjavascriptのminifyやmeta cssコンパイルといったフロントエンドにありがちな作業を自動化することができます。

gruntはそのエコシステムの作り方が非常にスマートで、npmをうまく活用して強力なエコシステムを作り上げたと思います。

この画像一枚に巧みさが集約されてるなーと思います。

f:id:yosuke_furukawa:20140217020106j:plain

Roommates | dontkry.com

画像の通り、gruntはフロントエンドツールの友達が多いです。

yeomanは事前にgrunt-cliをインストールするように言われてるし、bowerはbowerでgruntみたいなツールがないと片手落ちすぎて使いづらいです。こういう他のフロントエンド用のツールと親和性が高い。(@sindresorhusを中心に作られたエコシステムですね。)

また、そこから派生してwordpressのpublishに使われてたり、facebook Reactのモジュール群を構成する要素になっていたりもします。

最近はフロンエンド側のタスクだけに限らず、grunt-express-serverみたいなexpressの再起動もしてくれちゃったり、phpのlintとかもやってくれちゃうみたいです。元々フロントエンドためのツールだったはずがその枠組を超えてバックエンド側にも使えるツールとして広まっている訳です。

こうしてタスクランナーツールとして覇権を握るのは分かる気がします。誰だってタスクランナーツールを複数持つような事はしたくないし、一個のツールで楽に色んな事ができるならそっちを選びます。

makeや shell でタスクのオートメーションはできる

gruntでやってる事って make や shell でもできるよね、って思う人もいると思います。
実際にgrunt使ってない人ってmakeやshellで十分だと思ってる人も多いんじゃないかと思います。

ちょっと前にtask automationに関してsubstackが書いた記事があって、この記事にgruntじゃなくてもnpm runを活用すれば似たようなことは代替できるって事が書いてあります。

記事に書かれていることを要約しながら紹介します。

npmでtask automationをする場合

package.jsonのscriptsフィールドで任意のコマンドを書いておきましょう。

{
  "name": "my-silly-app",
  "version": "1.2.3",
  "private": true,
  "dependencies": {
    "browserify": "~2.35.2",
    "uglifyjs": "~2.3.6"
  },
  "devDependencies": {
    "watchify": "~0.1.0",
    "catw": "~0.0.1",
    "tap": "~0.4.4"
  },
  "scripts": {
    "build-js": "browserify browser/main.js | uglifyjs -mc > static/bundle.js",
    "build-css": "cat static/pages/*.css tabs/*/*.css",
    "build": "npm run build-js && npm run build-css",
    "watch-js": "watchify browser/main.js -o static/bundle.js -dv",
    "watch-css": "catw static/pages/*.css tabs/*/*.css -o static/bundle.css -v",
    "watch": "npm run watch-js & npm run watch-css",
    "start": "node server.js",
    "test": "tap test/*.js"
  }
}

scriptsフィールドに記述するとnpmコマンドのrunで実行できるようになります、この機能を利用して、

$ npm run watch

とか

$ npm run build

とか実行するとpackage.jsonに記述された文字列をコマンドとして実行してくれるわけです。

package.jsonに記述しきれないような複雑なコマンドを実行させたいのであれば、binフォルダ以下にでもshellスクリプトを作成しておいて、それを実行させればいいです。

bin/build.sh

#!/bin/bash
(cd site/main; browserify browser/main.js | uglifyjs -mc > static/bundle.js)
(cd site/xyz; browserify browser.js > static/bundle.js)

package.json

"build-js": "bin/build.sh"

ちょっと脱線しますが、watchify, catw は両方共substack製のツールでそれぞれwatchしてbrowserifyするコマンドとwatchしてgrabで記述されたファイルをconcatするコマンドです。

watchifyやcatwをやると、変更を検知してタスクを実行するというgrunt-contrib-watchライクな処理がコマンドから実行可能になります。

npm、make、shell vs modern tools

例を見てもらったとおり、npmやshellでもgruntと同様なことはできます。

それになるべくbasicなものを使っていたほうがgrunt, gulpなんかのフロントエンドツールに振り回されなくて済むし、新たなツールへの学習コストも減ります。

とはいっても、複雑なことをshellとかnpmでやらせようとするとやっぱり秘伝のタレ化しやすく、それはそれで問題があります。

そこへ行くと、gruntやgulpなんかのツールはエコシステムが素晴らしく、自分達でゼロから記述しなくても、やりたいことが実現できるようになっています。またもしも自分の望む処理が無かったとしてもgruntやgulpでタスクを作成できますし、それを公開することで他のgruntユーザーを幸せにすることができます。

結局ここまで引っ張っておきながら何なんですが、gruntやgulpみたいなモダンなツールはツールでpro, conがあるし、npmやshellスクリプトみたいなbasicなツールはツールでpro, conがあるので、最終的な着地点は好み、とかケースバイケースになってしまうんじゃないかなと思ってます。

またしても若干の脱線

koaのテストってまったくもってgrunt使ってないんですけど、それに対してツッコミを入れた人がいて、ちょっと翻訳すると、

Question: Why Make and not Grunt? · Issue #167 · koajs/koa · GitHub

質問者: koaってmake使ってるけどgrunt使わないの?

回答者(jonathan):逆になんでgrunt使うの?windowsサポートとかはともかく、makeで十分じゃない?

質問者:いや、それって十分な理由だと思うけど。(windows サポート)

回答者(TJ):windowsでもやろうと思えばmakeできるし、別に十分でしょ。

こんな感じで、質問者も回答者も噛み合っていない感じですが、別にいらないと思うプロジェクトにはそれでいいと思います。

だからgruntってこんなに仕事させるべきツールだったっけ、というふうになるのはすごく良くわかるんですけど、いい方法は見つかってないです。gruntとshell, npm, makeで適切な住み分けができるといいんですけど、Aっていうタスクはgruntで、Bっていうタスクはnpmで、みたいにしちゃうと覚えるコマンドが増えてそれはそれで微妙です。

大した事をしないならgruntは確かにオーバースペックで、shellで十分です。変更検知してjsに変換するとかconcatする位ならshellでも実現できます。また、shellやnpmで実施するほうが学習コストは減ると思います。ただ、こういうタスクをゼロから自分で書きたくない、gruntの強力なエコシステムに乗って複雑なことを楽に実施することを望むのであればgruntを使ったほうがいいです。