最近のオレオレconcatパターンとか

concatパターンの小ネタ

最終的には、1つに結合される予定の個別ファイル ( 例 Phalanx/src/view.js ) において

  • (そのファイル内の)グローバルに use strict 書いておきたい
  • ひとつひとつにファイルに即時実行関数パターンを書きたくない
'use strict'

var View = defineClass({
  constructor: function() {
    // 初期化とか
  },
  // 以下クラス定義
});

こんな感じで、余計なラップを書かずに1ファイルの中身を完結させたい。

という条件を満たすために下記のような grunt-concat の設定を使っている。

var RE_USE_STRICT_STATEMENT = /(^|\n)[ \t]*'use strict';?\s*/g,
    BANNER_TEMPLATE_STRING  = '/*! <%= pkg.name %> - v<%= pkg.version %> ( <%= grunt.template.today("yyyy-mm-dd") %> ) - <%= pkg.license %> */',
    BUILD_ORDERED_LIST = [
        // 結合順序のファイルリスト
        // 大抵ディレクトリ単位の大雑把指定なので最初に書いたらそれっきり
    ];
grunt.initConfig({
  concat: {
    options: {
      stripBanners: false,
      banner: [BANNER_TEMPLATE_STRING,
               '(function(window) {',
               '',
               '"use strict";',
               '',
               ''].join('\n'),
      footer: ['',
               '})(window);'].join('\n')
    },
    dist: {
      src: BUILD_ORDERED_LIST,
      dest: 'dist/all.js',
      options: {
        process: function(content) {
          return content.replace(RE_USE_STRICT_STATEMENT, '$1');
        }
      }
    }
  }
});

結合時の細工

やってることは単純で

  1. 個別ファイルの use strict を切り取る
  2. 結合する
  3. banner として即時関数パターンの頭と use strict をつける
  4. footer として即時関数パターンの尻をつける
  5. できあがり

という感じで

(function(window) {
`use strict`;

// 結合ファイル1つ目
var Model = defineClass({});

// 結合ファイル2つ目
var View = defineClass({});

// 結合ファイル3つ目
var Layout = defineClass({});

// 結合ファイル以下つらつら

})(window);

のようなファイルを生成する。例えばZeptoの結合ファイルと比べると、大分クリーンな感じになっているはずだ。

即時関数パターン内のローカル変数展開

ついでに、config.js 的な位置づけのファイルを結合の先頭にもってきて、下記のように記述している。

1つに結合しているのに OwnApp.View.Model.Hoge のように、グローバルのNSから記述して呼び出すのがアレなので、大抵は即時関数パターン内のローカル変数として参照を置いている。

'use strict';

var NS = 'OwnApp',
    App, Model, Layout, View, Component, Util, Config;

// オブジェクトをローカル変数と名前空間内に配置
var App        = window[NS]     = {};
var Model      = App.Model      = {};
var Layout     = App.Layout     = {};
var View       = App.View       = {};
var Component  = App.Component  = {};
var Util       = App.Util       = {};
var Config     = App.Config     = {};

これはまぁ、なんか皆いろいろやってそう。

結合順について

RequireJSを紹介するときに、Dependency Hellの話を挙げたことはあるが、結局ターゲットが1ファイル結合である限りは、継承(JSは疑似実装extend)を変に頼らなければ問題にならない。

var BUILD_ORDERED_LIST = [
  'conifg.js',
  'mixins/**/*.js',
  'models/**/*.js',
  'collections/**/*.js',
  'views/**/*.js',
  'layouts/**/*.js'
];

自分は最近、継承だけでコトを考えるのめんどいわーと思っているので、ちょうどいい感じなのである。

RequireJSは、依存関係を解決するためにRequireJSそのものを解決しなくてはならない本末転倒感を感じることが多くて、最近あんまり使っていない。

そんな感じでした!