実際にはどれだけの需要が有るか分からないけど、gruntのモジュールを作成してみました。
ブラウザとNode.jsで両方使えるjavascriptを記述するのに、ここやここやここにも投稿があるんですが、今回gruntとRequireJSでやってみたらすっげー楽なんじゃないか?と思ってモジュールを作ってみたので公開します。
何が楽なの?
普通にNode.js側のコードだけを記述すれば、ブラウザ側のコードに変換しちゃいます。
先のような投稿のハックは不要(になるはず?)です。
しかも、クライアントでもモジュール毎にファイルを作成できるし!管理も楽!
使い方
readme.mdじゃなくて、次の手順で体験したほうが理解が早いです。
手順どおり打てばいいだけなんですが、mac環境であることを前提にしています。
(winの方は申し訳ない)
- まず何はともあれ、gruntを使えるようにします。
+sudo npm install -g grunt-cli
+ gruntについてちゃんと理解したい人はドットインストールが一番早いよ - 空のディレクトリを適当に作成しそこに移動
+mkdir tutorial
+cd tutorial - 今回公開しているモジュールのgrunt-m2rをnpm経由でインストール
+npm install grunt-m2r - node_modules/grunt-m2rのexampleフォルダの中身を先のディレクトリに複製
+cp -r ./node_modules/grunt-m2r/example/* . - 必要モジュールをインストール
+npm install - gruntを走らせてみる
+grunt - index.htmlをブラウザで開く
- コンソールを確認する
+ 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を有効にすると手間いらずです。
- Gruntfile.jsのtaskでwatchを有効にする
- manualの行をコメントアウト
- autoの行のコメントをはずす
- index.htmlの自動リロードを有効にする
- livereload.jsのスクリプトのコメントアウトをはずす
- gruntを走らせる
grunt
- 終了する場合はCtrl+c
これで、ブラウザを開いたままnodeの変更すると、ブラウザの方まで自動更新されます
ただ、変換対象のファイルが増えてくると、gruntがどんどん重くなるので、自動更新は程々がよさそうかな?
nodeの標準モジュールは使えない?
このままじゃ、nodeの標準のモジュールをクライアントで使用出来ません。
さすがに、全部移植なんて無理なのであきらめます。
でも、いくつか便利なものは使いたいなーと思ってeventsとutil.inheritsだけ移植してみました。
ここら辺は付け焼き刃なので、utilはinherits以外は実装していません
それぞれ、util.js, events.jsをsrcフォルダに入れるだけで、ブラウザでも
EventEmitterを継承する事ができるようになります。
ただし、簡略して記述しないでください。
// これは無理
var EventEmitter = require('events').EventEmitter;
require('util').inherits(Klass, EventEmitter);
grunt-m2rのコンパイラがそこまでは頭は良くないので、次のようにお願いします
// これはOK
var events = require('events');
var util = require('util');
util.inherits(Klass, events.EventEmitter);
さいごに
例のごとく、テストが不十分です。不具合はissueを入れてくれると助かります。
あと、m2rの意味はmodule to requirejsです。
gruntのモジュールを作るのは初めてでしたので、いろいろ戸惑いました。
grunt-pluginの作り方と解剖がすごく参考になりました。fnobiさんありがとう!
RequireJSも今までは採用していなかったのですが、gruntと一緒に使うことで楽になるので、本格的に使ってみようかな。
追記
(2014/6/3)モジュールのバージョンアップに伴い、記事を修正しました
(2014/6/22)モジュールのバージョンアップに伴い、記事を修正しました