rejs - Vanilla JS Module Builderの紹介
このエントリは GREE Advent Calendar 2014 6日目の記事です。
皆さんこんにちは!Reflowしてますか?
13卒でArt部の和智(@watilde)です。業務では、GREE Platformで使われている内製 JS/CSS FrameWorkのコミッターとかしてます。
まえがき
弊社は、スマートフォンの黎明期よりブラウザ向けのアプリを開発してきました。環境の変化への追従や、度重なる機能追加でJavaScriptのコードの規模は肥大化していきました。
役割ごとにモジュール化をしてファイル分割を行わないと可読性が落ち、じわじわと保守コストが上がっていきます。しかし、古くからある秘伝のソースはAMDやCommonJSで書かれていないVanillaなJSです。r.js、Browserify、Webpack などのツールでモジュール化するにも、書き換えが大量に発生して導入するのはとっても②大変です。
そんな背景から、Vanilla JSのモジュール化を行う第一歩として、rejsと呼ばれるVanilla JSのModule Builderがグリーでは利用されています。今回は、そんなrejsの紹介を行います!
rejs - Vanilla JS Module Builderの紹介
rejsは、グリーに所属するJason Parrottによって開発されているOSSなVanilla JS Module Builderです。グリーでは、一部のゲームや内製のライブラリ開発で使用されています。
URL: https://github.com/Moncader/rejs
rejsの説明をVanilla JS Module Builderとしてみましたが、分かりやすく言うと「ファイルのリストをその内容に基づいてソートしてくれるツール」となります。
明確にexport/importの機能があるわけではありませんが、exportは「グローバルにプロパティ生やす」で、importは「ファイルに存在しないものを参照する」なのでModule Builderとして成立していると考えています。
仕組み
簡単に処理の流れについて
- ファイルの名前とソースを受け取る
- acornを使い、ファイルごとにソースのASTを取得
- ASTのNodeごとにファイルのGlobal Scopeにある変数の詳細とその状態を保持
- ファイルのGlobal Scopeごとに、内部で定義している変数と使用している変数を解析
- 以上を元に、依存関係を解決するように各Nodeを順序付けしてソート
実際に使ってみる
rejsを使うには、3つの方法があります。
- rejsのcli
- gruntプラグイン
- gulpプラグイン
ぞれぞれ、実際に使ってみましょう。
構成例
いきなり使う前に、まずはファイル構成についての説明です。
下記のようなディレクトリ構成を例に話を進めていきます。
- src
- sampleOne.js
- sampleTwo.js
- sampleThree.js
- dist
- XmasPresent.js
- test
- fixture.js
- test.js
srcディレクトリ内にソースファイルがあり、
distディレクトリに依存関係を解決し、結合済みのXmasPresent.jsを書き出すという想定です。
次に、それぞれのソースファイルについての説明します。
sampleOne.js
グローバル空間に宣言済みであろうxmasオブジェクトの
present.box.colorというプロパティにredという文字列を入れています。
1 2 3 4 5 |
(function(global) { global.xmas.present.box.color = 'Red'; }(this)); |
sampleTwo.js
グローバル空間に宣言済みであろうxmasオブジェクトに
present.boxというプロパティを追加しています。
1 2 3 4 5 6 7 |
(function() { xmas.present = { box: {} }; }()); |
sampleThree.js
グローバル空間にxmas
というオブジェクトを宣言しています。
1 |
var xmas = {}; |
さて、今回のケースでは
sampleThree.js, sampleTwo.js, sampleOne.jsの順に結合すれば正しく動作します。
期待する振る舞いとして、結合したものと比較して何も表示されなければOKとします。
1 2 |
$ cat src/sampleThree.js src/sampleTwo.js src/sampleOne.js > dist/fixture.js $ diff dist/*.js |
使ってみる
環境を構築したら、次は実際にコンパイルをしてみます。
cli
npm経由でrejsコマンドをインストールできます。
1 |
$ npm install -g rejs |
使い方は、-hオプションで見ることができます。
1 2 3 4 5 6 7 8 9 10 11 12 |
$ rejs -h Usage: rejs [options] [file ...] Examples: rejs foo.js bar.js baz.js rejs --out out.js foo.js bar.js baz.js Options: -h, --help Print this message -o, --out Output to single file -v, --version Print rejs version |
基本的な使い方は、rejs [options] [files ...] となっており、-o オプションで書き出すファイル名を指定することができます。
今回は、distディレクトリにXmasPresent.jsとして書き出せばいいので、下記のコマンドを実行すれば完了です。
1 |
$ rejs --out dist/XmasPresent.js src/*.js |
Gruntプラグイン
次に、rejsの作者が開発しているGruntプラグインを用いたコード例です。
URL: https://github.com/Moncader/grunt-rejs
Gruntfile.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
module.exports = function(grunt) { grunt.initConfig({ rejs: { options: {}, target: { files: { 'dist/XmasPresent.js': 'src/*.js', } } } }); grunt.loadNpmTasks('grunt-rejs'); }; |
registerTaskを省略していますが、
grunt.configのプロパティを使いタスクを走らせてビルドしてみましょう。
1 2 3 4 5 6 |
$ grunt rejs Running "rejs:target" (rejs) task File "dist/XmasPresent.js" created. Done, without errors. |
これで、dist/XmasPresent.jsがビルドされます。
gulpプラグイン
最後に、@kuuが開発しているgulpプラグインを用いたコード例を紹介します。
URL: https://github.com/kuu/gulp-rejs
READMEを参考に、gulpfileを書きます。
gulpfile.js:
1 2 3 4 5 6 7 8 |
var gulp = require('gulp'); var rejs = require('gulp-rejs'); gulp.task('rejs', function () { return gulp.src('src/*.js') .pipe(rejs('XmasPresent.js')) .pipe(gulp.dest('dist')); }); |
コマンドを実行してビルドしてみましょう。
1 2 3 4 5 |
$ gulp rejs [11:29:55] Using gulpfile ~/Development/rejs-example/gulpfile.js [11:29:55] Starting 'rejs'... [11:29:55] Finished 'rejs' after 22 ms |
やっぱりgulpfile見やすくて良いですね。
Code example on Github
これにてrejsの紹介はおしまいです!
下記URLにて本エントリに出てくるソースコード一式を公開してあるので、
ご自由にご利用くださいm(_ _)m
URL: https://github.com/watilde/rejs-example
あとがき
今後もグリーでは、社内で開発したライブラリを公開したりOSSコミュニティに貢献していきます。
クリスマスを待つ間、引き続きGREE Advent Calendar 2014をお楽しみ頂ければ幸いです!
明日はマーケティング部の戸井田明俊さんと情報システム部の亀井利光さんです。
参考資料
記事の補足として、記事内で出てきたツールやライブラリのURLと用語の説明を載せておきます。併せてご覧頂ければと思います。
URL(s)
- https://github.com/amdjs/amdjs-api/wiki/AMD
- http://www.commonjs.org/
- http://requirejs.org/docs/optimization.html
- http://browserify.org
- http://webpack.github.io/
- https://github.com/Moncader/rejs
- http://gruntjs.com/
- https://github.com/Moncader/grunt-rejs
- http://gulpjs.com/
- https://github.com/kuu/gulp-rejs
- https://github.com/watilde/rejs-example
用語
- Vanilla JS Module: グローバル・ネームスペースを介してシンボルをexport/importする従来のJavaScriptコード