requirejsをbowerでインストールしてgruntでビルドする


私はJSを書くときはAMD推奨派なので、比較的大きめのアプリを作るときはまずrequireJSなどを使用します。
requirejsを使ってモジュールを作成すると依存関係が明確になり、テンプレートなどもrequirejs-textなどを使用すれば再利用がとても容易な形で記述することができます。

ただし、AMD時の一つの懸念点としてビルドして依存モジュールをconcat&uglifyしなくてはパフォーマンスがでないという点が挙げられます。そこで探してみるとgruntのtaskモジュールで内部的にr.jsを使用してビルド(依存モジュールの連結+compress)を行ってくれる便利ツールを発見。これを使えばパフォーマンスに関する問題は大丈夫でしょう。
以下、少し長いですがセットアップ手順です。

例えば以下のようなnode+express環境を想定しています。

app
 - /bin
 - /bower_components
 - /public
   - /css
   - /dist -> サーバーデプロイ用ビルドされたjsが置かれる
       - teji.your_app.main.js
   - /img
   - /js -> 開発AMDモジュール
       - /lib -> bowerでインストールされているJSライブラリから必要なものがgruntでコピーされる
            - /jquery
            - /requirejs
            - /requirejs-text
       - /teji
           - /your_app
              - main.js
              - /model
              - /view
 - /routes
 - /views
 - app.js
 - bower.json
 - Gruntfile.js
 - package.json

まず、bowerでrequirejsとrequirejs-textをインストールします。

bower install requirejs --save
bower install requirejs-text --save

/bower_components以下にライブラリがインストールされると思います。そこから必要なモジュールだけをpublicのディレクトリに配置したいため、gruntのbower installタスクを使用します。

Grunt内でbowerタスクを使用するために、以下のようにgrunt-bower-taskをインストールします。
npm install grunt-bower-task --save-dev

Gruntfile.jsでは以下のようなタスクエントリを追加します。

    grunt.initConfig({
        bower: {
            install: {
                options: {
                    targetDir: 'public/js/lib',
                    layout: 'byType',
                    install: true,
                    verbose: false,
                    cleanTargetDir: true,
                    cleanBowerDir: false
                }
            }
        },

このように記述すると、bower_components以下の依存ライブラリディレクトリから、ライブラリディレクトリ内のbower.json内のmainで指定されたファイルをpublic/js/lib以下に配置してくれます。
もしmainが正しく指定されていなくて、public/js/lib以下に不要なファイル群がコピーされてしまう場合は以前の記事「gruntのbower installでtargetDirにcopyするファイルを制御」を参考にしてください。

あとセットアップとしてはhtmlからrequirejsを読み込むのと、reuqirejsのconfigの記述が必要です。
簡単な記述例。

view/index.html

<script data-main="/dist/teji.your_app.main.js" src="/js/lib/requirejs/require.js"></script>

上記のhtml内ではdistディレクトリ以下のビルド済みのjsを指定します。
ビルド前のrequirejsのconfigが入っているファイルを作成します。

public/js/teji/your_app/main.js

requirejs.config({
    baseUrl: "/js",
    paths: {
        "jquery": "lib/jquery/jquery",
        "text": "lib/requirejs-text/text",
        "bootstrap": "lib/bootstrap/bootstrap"
    },
    shim: {
       "bootstrap": {
          deps: ["jquery"]
        }
    }
});

require(["jquery", "bootstrap"], function($, bootstrap) {
    console.log("loaded");
});

上記の例ではjqueryやbootstrapもついでに入れていますが、使わない場合は必要ないです。使うためにはbowerでrequirejsをインストールしたときと同様にbower install jquery --savebower install bootstrap --saveコマンドを発行しましょう。

さて、最初に読み込まれるAMDのファイルを作成できたので、gruntでビルドできるようにしましょう。
r.jsを使ってビルドを実行してくれるnodeのモジュールgrunt-contrib-requirejsをインストール。

npm install grunt-contrib-requirejs --save-dev

その後、Gruntfile.js内でタスクを記述。

Gruntfile.js

        requirejs: {
            dev: {
                options: {
                    baseUrl: 'public/js',
                    name: 'teji/your_app/main',
                    mainConfigFile: 'public/js/teji/your_app/main.js',
                    out: 'public/dist/teji.your_app.main.js',
                    optimize: 'none'
                }
            },
            production: {
                options: {
                    baseUrl: 'public/js',
                    name: 'teji/your_app/main',
                    mainConfigFile: 'public/js/teji/your_app/main.js',
                    out: 'public/dist/teji.your_app.main.js'
                }
            }
        }

このタスクでAMD形式でばらばらに書いたモジュールの先頭のもの(今回はpublic/js/teji/your_app/main.js)から依存モジュールを辿って、順次くっつけていったものを一つのファイルとしてpublic/dist/teji.your_app.main.jsに出力してくれます。

また、上記では開発用にcompressしないモードとproduction用にcompressするモードで分けています。
gruntのデフォルトのタスクでは開発用タスクを用いるため以下のように指定します。

Gruntfile.js

    grunt.registerTask('default', [
        'bower:install',
        'jshint',
        'requirejs:dev',
        'shell:start',
        'watch'
    ]);

watchタスクではjsの変更をチェックして、requirejsのビルドを走らせるようにします。大規模なアプリでない限りcompressionを行わなければ、さくさくビルドは完了するはずです。

Gruntfile.js

        watch: {
            src: {
                tasks: ['jshint', 'requirejs:dev'],
                files: ['./**/*.js']
            }
        },

少々長くなりましたが、一度上記の手順でアプリ開発の始めにgruntのタスクをセットアップしておけば、requirejsでさくさく開発始められるはずですー

本当は、上記セットアップ後の雛形をyeomanでgenerateしてしまうのがカッコイイかw
暇があったら、express+jquery+bootstrap+requirejsのgeneratorを作りたい。