LoginSignup
5
5

More than 5 years have passed since last update.

Multipage版のBackbone Yoman Generatorを公開しました

Last updated at Posted at 2014-04-29

はじめに

Backbone用のYoman Generatorを公開しました。
https://github.com/cgetc/generator-backbone-multipage
ポイントをざっと説明します。

複数ページでのrequire.js

  • require.configのbaseUrlを設定しないと、JSの非同期読み込みの際のパスが変わる
  • 共通で使用するファイル(common.js)を単一ファイルにまとめた
  • require.configをrequire.jsに含めた(HTTPリクエストを減らすため)
  • 各ページで使用するファイル(page/*.js)を単一ファイルにまとめた

※以前はrequire.jsをcommon.jsに含めていたが、そうすると、common.jsを読み込むまでブロッキングしてしまうため、require.jsとcommon.jsを切り離した。

開発環境と本番環境の切り替え

  • require.jsに環境ごとの設定部分をGruntで結合して切り替える。
  • 開発環境はminifyしないソースを直接参照する様になっている。
Gruntfile.js
function generate_develop_require_js () {
    var options = _.pick(get_requirejs_options('develop'), ['paths', 'shim', 'urlArgs']);
    options.baseUrl = '/' + jsDir;
    delete options.paths.requirejs;
    grunt.file.write(outJsDir + '/require.js', [
        grunt.file.read('./node_modules/requirejs/require.js'),
        'require.config(' + JSON.stringify(options) + ');'
    ].join('\n'));
}
  • 本番環境はrequire.jsはminifyされたソースを参照する
Gruntfile.js
function generate_build_require_js () {
    var options = _.pick(get_requirejs_options('build'), ['urlArgs']);
    options.baseUrl = '/' + outJsDir;
    grunt.file.write(jsDir + '/require.js', [
      grunt.file.read('./node_modules/requirejs/require.js'),
      'require.config(' + JSON.stringify(options) + ');'
    ].join('\n'));
}
  • 本番環境はrequire.jsにmodulesオプションを指定して結合する
  • 共通JSはincludeを指定し、各ページのJSはexclueを指定する
  • このオプション指定でコード内でrequireされていなくても結合される
Gruntfile.js
grunt.config(['requirejs', 'build', 'options', 'modules'], generate_requirejs_build_modules());
grunt.task.run('requirejs:build');

function generate_requirejs_build_modules () {
    var libs =  _.keys(config.requirejs.paths),
        modules = [{
          name: 'common',
          include: libs
        }];
    grunt.file.recurse(jsDir + '/page', function (abspath, rootdir, subdir, filename) {
      var dir = subdir? subdir + '/' : '';
      modules.push({
        name: 'page/' + dir + filename.slice(0, -3),
        exclude: libs
      });
    });
    return modules;
}

HTMLからrequire.jsモジュールへの変数の渡し方

  • 各ページのJSをFunctionのモジュールとして定義する
page/todo.js
define(['backbone', 'collection/Todos', 'view/todo/ListView'], function (Backbone, Todos, ListView) {
    return function (todo_list) {
        var todos = new Todos();
        view = new ListView(todos);
        todos.set(todo_list);
        new Router();
        Backbone.history.start();
    };
});
  • 各ページのJSをrequireし、引数としてJSONを渡す
inex.html
<script>
    require(['page/todo'], function (load) {
        load([
            {id: 1, title: 'hoge', description: 'hogehogehoge'},
            {id: 2, title: 'fuga', description: 'fugafugafuga'}
        ]);
    });
</script>

テンプレート管理

  • JSTテンプレートをgrunt-contrib-jstでJSにプリコンパイルする
  • {namespace: false, amd: true}をオプション指定するとグローバル変数なしのAMD形式で出力される
  • デフォルトではwith文を使うためtemplateSettings:variableオプション指定して抑制する
Gruntfile.js
grunt.initConfig({
    jst: {
      options: {
        namespace: false,
        amd: true,
        templateSettings: {
          variable: 'data'
        }
      }
    }
});
tmpl/todo/ListView.ejs
<li>
    <a href="#description/<%= data.id %>"><%= data.title %></a>
</li>
  • JSファイルなのでrequire.jsで読み込める
ListView.js
define(['backbone', 'tmpl/todo/ListView'], function (Backbone, listTmpl) {
    return Backbone.View.extend({
        el: '#todo-list',
        template: listTmpl,
    });
});

雑感

  • Backbone.jsは本来SPA(シングルページアプリケーション)を作成するものだが、規模が大きくなると分割した方がよいと考え、複数ページのベストプラクティスを模索した。
  • require.jsの設定部分をGrunt.js内で書き出す以外に方法はないものか?(SPA前提であれば、data-mainで読み込めばいい)
  • HTMLからrequire.jsモジュールへの変数の渡し方は他にないものか?(scriptタグ内にBackbone.jsのマウントポイントを置くよりはこちらの方が好み。)
  • Backbone.jsにはtextプラグインがあるが、JSTをプリコンパイルした方が、パフォーマンス上優位なのは当然だが、テンプレートのフォルダもjsフォルダ配下に置かなくて済むのもメリット。
  • テンプレートファイルの読み込みもrequire.jsで都度結合できるようになるメリットもある。

その他

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5