ブラウザ、Node.jsで両方使えるjavascriptをgruntで自動化


実際にはどれだけの需要が有るか分からないけど、gruntのモジュールを作成してみました。

ブラウザとNode.jsで両方使えるjavascriptを記述するのに、[ここ](http://qiita.com/armorik83/items/78bd3d785d0a97c82711)や[ここ](http://qiita.com/VoQn/items/325a17063c4f6c61761c)や[ここ](http://qiita.com/ishiduca/items/cd6b27e80ae7c3435eb0)にも投稿があるんですが、今回gruntとRequireJSでやってみたら<strong>すっげー</strong>楽なんじゃないか？と思ってモジュールを作ってみたので公開します。

[github - grunt-m2r](https://github.com/yukik/grunt-m2r)

# 何が楽なの？

普通にNode.js側のコード<strong>だけ</strong>を記述すれば、ブラウザ側のコードに変換しちゃいます。
先のような投稿のハックは不要（になるはず？）です。
しかも、クライアントでもモジュール毎にファイルを作成できるし！管理も楽！

# 使い方

[readme.md](https://github.com/yukik/grunt-m2r/blob/master/README.md)じゃなくて、次の手順で体験したほうが理解が早いです。
手順どおり打てばいいだけなんですが、mac環境であることを前提にしています。
(winの方は申し訳ない)

  1. まず何はともあれ、gruntを使えるようにします。
    + `sudo npm install -g grunt-cli`
    + gruntについてちゃんと理解したい人は[ドットインストール](http://dotinstall.com/lessons/basic_grunt)が一番早いよ
  1. 空のディレクトリを適当に作成しそこに移動
	+ `mkdir tutorial`
	+ `cd tutorial`
  1. 今回公開しているモジュールのgrunt-m2rをnpm経由でインストール
    + `npm install grunt-m2r`
  1. node_modules/grunt-m2rのexampleフォルダの中身を先のディレクトリに複製
    + `cp -r ./node_modules/grunt-m2r/example/* .`
  1. 必要モジュールをインストール
    + `npm install`
  1. gruntを走らせてみる
    + `grunt`
  1. index.htmlをブラウザで開く
  1. コンソールを確認する
    + chromeなら`option + command + j`
    + `foo say hello`と`bar say hello`が表示されていると成功！！！

# 解説

libにはnodeのjsがsrcにはブラウザのjsが配置されています。
lib以下のファイルを更新後に、gruntを走らせるとsrcフォルダが作成されファイルが変換されます。
foo.jsとbar.jsが作成されているはずです。
index.htmlはRequireJSを使用してmain.jsから順にsrc/foo.js,src/bar.jsを呼び出しています

一方node側でも動作させてみたい場合は、サンプルではapp.jsをエントリポイントとして作ってあるので、`node app.js`としてみるとブラウザと同じ表示がされると思います。


変換処理自体は単純です。
  + ファイルにコメント`/*grunt-m2r*/`がある場合は変換できるファイルと判別します
  + `var foo = require('foo');`の記述があったら、ひたすらRequireJSの事前読み込みモジュールに設定
  + `exports.bar = ...`とかあるなら、最後に`return exports;`を追加
  + もしくは`module.exports = baz;`を`return baz;`にする

コレくらいしかしていません。

# 自動変換でもっと楽に

もし、nodeの方のjsを更新するたびに、自動的にブラウザ側のjsを変換したい場合はwatchを有効にすると手間いらずです。

 1. Gruntfile.jsのtaskでwatchを有効にする
    + manualの行をコメントアウト
    + autoの行のコメントをはずす
 1. index.htmlの自動リロードを有効にする
    + livereload.jsのスクリプトのコメントアウトをはずす
 1. gruntを走らせる
    + `grunt`
 1. 終了する場合はCtrl+c

これで、ブラウザを開いたままnodeの変更すると、ブラウザの方まで自動更新されます
ただ、変換対象のファイルが増えてくると、gruntがどんどん重くなるので、自動更新は程々がよさそうかな？

# nodeの標準モジュールは使えない？

このままじゃ、nodeの標準のモジュールをクライアントで使用出来ません。
さすがに、全部移植なんて無理なのであきらめます。
でも、いくつか便利なものは使いたいなーと思ってeventsとutil.inheritsだけ移植してみました。
ここら辺は付け焼き刃なので、utilはinherits以外は実装していません

 + [util - github](https://github.com/yukik/nodify-util)
 + [events - github](https://github.com/yukik/nodify-events)

それぞれ、util.js, events.jsをsrcフォルダに入れるだけで、ブラウザでも
EventEmitterを継承する事ができるようになります。
ただし、簡略して記述しないでください。

```js:
// これは無理
var EventEmitter = require('events').EventEmitter;
require('util').inherits(Klass, EventEmitter);
```

grunt-m2rのコンパイラがそこまでは頭は良くないので、次のようにお願いします

```js:
// これはOK
var events = require('events');
var util = require('util');
util.inherits(Klass, events.EventEmitter);
```

# さいごに

例のごとく、テストが不十分です。不具合は[issue](https://github.com/yukik/grunt-m2r/issues)を入れてくれると助かります。
あと、m2rの意味はmodule to requirejsです。
gruntのモジュールを作るのは初めてでしたので、いろいろ戸惑いました。[
grunt-pluginの作り方と解剖](http://qiita.com/fnobi/items/5590e7e92b4f2bd81d04)がすごく参考になりました。fnobiさんありがとう！
RequireJSも今までは採用していなかったのですが、gruntと一緒に使うことで楽になるので、本格的に使ってみようかな。


# 追記

(2014/6/3)モジュールのバージョンアップに伴い、記事を修正しました
(2014/6/22)モジュールのバージョンアップに伴い、記事を修正しました