yutaponのブログ

javascript界隈の興味あるネタを備忘録的に残しておく場所

RequireJSの導入から使い方(Bowerにも触れてみる)

Backbone.jsのRouter編を書く前にどうしてもRequireJSについて
おさらいしておきたく書いてみる。

あまり深くRequireJSについて理解してなかったこともあり、
結構調査したので理解が深まった。

それと今まで使ったことなかったけどBowerにも触れてみる。


結構長いのでアウトラインを。

  • 環境整備
    • Bowerでライブラリを管理する
  • RequireJSの使い方
    • HTML側の記述
    • JS側の記述
    • モジュールの作り方
  • おわりに



環境整備

今回は新しいexpressプロジェクトを作成して環境を整備していきます。

$ cd path/to/workspace  # 作業ディレクトリに移動して
$ express -e -c stylus requirejs # ejs, stylusを有効にしてrequirejsというプロジェクトを作成 
$ cd requirejs  # プロジェクトのディレクトリに移動

ここでのディレクトリ構成はこんな感じ。

$ tree -L 1
.
├── app.js
├── node_modules
├── package.json
├── public   # webサーバによって公開されるディレクトリ
├── routes
└── views



Bowerでライブラリを管理する

Bowerというフロントエンドのパッケージマネージャーを使うと
有名ドコロのライブラリをサクッとインストールすることができます。
Bower - A package manager for the web

Bowerをnpmでインストールをします。

$ npm install -g bower  # グローバルに入れる

Bowerを使ってインストールするパッケージは、デフォルトだと
$ bower init したディレクトリに bower_components/ という
ディレクトリが作成されてそこにインストールされます。

でもjsファイルは public/ 以下に置きたいので、
配置場所を変更する .bowerrc を作成します。

$ vim .bowerrc  # プロジェクト直下に作る
...
# @file .bowerrc  ↓このようなjsonを作る
{
  "directory": "public/bower_components",
  "json": "bower.json"
}

directoryにインストール先のディレクトリを書いて、
jsonにbower.jsonへのパスを記述します。


.bowerrcができたらinitしてbower.jsonを作ります。
いろいろ聞かれますが都度入力して下さい。最初は全部エンターで良いかと。

$ bower init
... # とりあえずエンター押していく

こんな感じのファイルができました。

$ cat bower.json
{
  "name": "test",
  "version": "0.0.0",
  "authors": [
    "yutapon <hogehoge@fuga.com>"
  ],
  "license": "MIT",
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "public/bower_components",
    "test",
    "tests"
  ]
}


あとは必要なライブラリをインストールしていくだけ。

$ bower install requirejs jquery backbone --save
... # public/bower_components/ 以下にそれぞれインストールされる
    # 指定してないけど underscore.js もインストールされる

ライブラリが他のライブラリに依存していたら依存先も自動的にインストールされます。
backboneはjqueryとunderscoreに依存していると思ってたら、
bower上はunderscoreにだけ依存しているみたい。

パッケージの検索は search で探して、パッケージの削除は uninstall でできます。
用意ができたのでRequireJSの使い方をやります。


RequireJSの使い方

RequireJSを使う理由はモジュール化が一番かと思います。
読み込みが非同期になったり、依存関係を明示的にできるのもメリットですが、
ファイルをロジック単位に細かく分割して管理できるのが大きい。
RequireJS

こちらでも言及されてますが、規模が小さいうちは導入する必要性は感じません。
RequireJSを使うのを止めた理由 | それなりブログ

将来的にスケールしそうなサービスであれば導入しておくとよいかも。

HTML側の記述

ちなみに今までは↓のような書き方を紹介してきました。

<!-- BODYの下部で読み込む -->
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone-min.js"></script>
<!-- mail.js にロジックを記述する -->
<script src="javascripts/mail.js"></script>

RequireJSを使うとこうなります。

<!-- HEADの中で読み込む -->
<script data-main="javascripts/app.js" src="bower_components/requirejs/require.js"></script>

srcはいいとして、data-mainでは一番初めに実行するモジュールを指定します。
ここではjavascripts/app.jsを実行するように指定してみました。

JS側の記述

app.jsはページロード時の一番最初に実行されるモジュールであることから
RequireJSに関する設定を記述します。

また、モジュールは一つのファイルに1モジュールで作っていきます。

app.jsはこんなふうに書いてみました。

// @file app.js

// RequireJSの設定
requirejs.config({
    baseUrl : '/javascripts',  // モジュール読み込みのbaseUrlを指定する

    paths : {
        jquery : [
            '//code.jquery.com/jquery-2.1.0.min',      // 先に読み込される
            '/bower_components/jquery/dist/jquery.min' // 失敗したら次に読み込みされる
        ],

        underscore : [
            '//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.2/underscore-min',
            '/bower_components/underscore/underscore'
        ],

        // '/'または'http'から始まると絶対パスで参照する
        // それ以外はbaseUrlからみた相対パスになる
        backbone : '/bower_components/backbone/backbone'
    },

    shim : {
        underscore : {
            exports : '_'
        },
        // Backbone.js ver1.1.1 からAMDに対応したので下記の設定はいらなくなった
        // backbone : {
        //     deps : [underscore', 'jquery'],
        //     exports : 'Backbone'
        // }
    }
});

// モジュール定義
define(['backbone'], function (Backbone) {
    console.log(Backbone === window.Backbone);  // trueになる
});


configをそれぞれ詳しくみていきます。

baseUrl

モジュールを参照するときのベースとなるパスを記述します。
フロントのライブラリなどはpublic/bower_components以下において、
自作のJSはpublic/javascripts以下に置くという方針にするため、
baseUrlは/javascriptsにしました。

paths

baseUrlとモジュールIDからファイルを発見できない場合に使います。
baseUrlであるpublic/javascripts以外の場所に配置されたファイルは
ここに追記することとします。
モジュールIDとはrequirejs内で使うIDで、paths以下のプロパティがモジュールIDとなります。
jqueryとかunderscoreとかがモジュールIDとなります。

shim

define()を使っていない(AMD形式のファイルでない)ファイルに対して
モジュールの依存関係や、グローバル変数の名前を定義します。
depsでは依存関係を配列で指定し、exportsでグローバル変数を指定します。

モジュールの作り方

モジュールはdefine()で定義します。

↑で載せたモジュール定義部分を詳しく説明するとこんな感じ。

// define()の第一引数に配列でモジュールIDを指定している
// 'backbone'というモジュールIDはconfigのpathsで定義されている
// 第二引数の関数の引数にあるBackboneというのは、
// 第一引数で指定したモジュールを参照するための変数名
define(['backbone'], function (Backbone) {
    console.log(Backbone === window.Backbone);  // trueになる
});

こちらのコードは使う分にはいいんですが、
他のモジュールから呼ばれることを想定していません。

他のモジュールから呼び出されるようなモジュールを作るときは
defineにオブジェクトを渡します。

// オブジェクトの渡し方にはいろいろある

// @file javascripts/hoge.js
// だたオブジェクトを渡す
define({ hoge: 'hoge', fuga: 'fuga' });


// @file javascripts/func.js
// オブジェクトを返す関数を渡す
define(function () {
    return {
        val : 'value',
        func : function func() {
            alert('abcd');
        }
    };
});


// @file javascripts/ref_hoge.js
// モジュールを読み込んでオブジェクトを作る
define(['./hoge'], function (hoge) {
    var ref = {
        refHoge : hoge.hoge,
        refFuga : hoge.fuga
    };

    return ref;
});

define()で囲ったらオブジェクトを返すようすれば良いわけです。


モジュールの使い方をもう少し補足します。

// 第一引数に複数のモジュールIDを指定したら
// 関数の引数で指定する変数名はモジュールIDの順番と一致させる
define(['hoge', 'fuga'], function (hoge, fuga) {
    return {
        hoge : hoge,
        fuga : fuga
    };
});

// 依存するモジュールが多いなら、参照する変数名を対応させるのに
// 苦労するのでrequire('モジュールID')で参照を得ることができる
define(['a', 'b', 'c', 'd', 'e', 'f'], function () {
    var a = require('a');
    var b = require('b');
    return {};
});

これで大体RequireJSをどうやって使うか掴めたかと思います。
モジュール内はクロージャになっているのでグローバル変数を汚すことがないのも良いです。


おわりに

今までRequireJSを漠然としか理解してなかった。
よくよく調べればとても便利。
RequireJSのプラグインについても書きたいのであと1回くらいやるかも。