実際にはどれだけの需要が有るか分からないけど、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
が表示されていると成功!!!
- chromeなら
解説
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)モジュールのバージョンアップに伴い、記事を修正しました