jsファイルの依存性管理について

# requireJS
`js` ファイルの管理は `requireJS` が有名だ。
`requireJS` というのはかいつまんで言うと、

```html:index.html
<html>
  <head></head>
  <body>
    <script src="dondon.js"></script>
    <script src="dondoko.js"></script>
    <script src="dondokodon.js"></script>
    <script src="dokodondon.js"></script>
    <script src="dontakata.js"></script>
    <script src="dokatantan.js"></script>
    <script src="dokadoka.js"></script>
    <script src="dokashaba.js"></script>
    <script src="shabadosu.js"></script>
    <script src="shabadobi.js"></script>
    <script src="shabadobia.js"></script>
    <div>some contents</div>
  </body>
</html>
```

こいつを

```html:index.html
<html>
  <head></head>
  <body>
    <script src="scripts/require.js" data-main="scripts/main.js"></script>
    <div>some contents</div>
  </body>
</html>
```

```js:scripts/main.js
require.config({
  shim: {
    dondokodon: ["dondon", "dondoko"],
    dondokodon: ["dondoko"],
    dokatantan: ["dondokodon", "dokodondon", "dontakata"],
    dokadoka: ["dokatantan"],
    shabadobi: ["dondon"],
    shabadobia: ["dokatantan", "dokashaba", "shabadosu", "shabadobi"]
  },
  deps: ["shabadobia"]
});
```

こうしてくれる便利なモジュールだ。

両者の違いは、

- 前者：
    - ファイルリスト（= 「上にあるほど優先度高いよ」）によって管理している
- 後者：
    - ファイル（= 「このファイルを読み込む前に」）と、
    - ファイルリスト（= 「このファイル群が読み込まれている必要がありますよ」）の組によって管理している

「依存性」というのはまさにこの「ファイルとファイルリストの組」のことなので、後者のほうがより本質的な表現と言える。
（余談だがファイルに限らず、依存関係とは $X \times [X]$ の部分集合のことである、と定義できる）

requireJS には ファイル管理と同時にモジュールを管理する方法も提供されているが、angularJS の Dependency Injection の精神とバッティングしているので、angularJS と requireJS を併用する際には使用しない（その辺の考察はこちらを参考にした： https://github.com/CaryLandholt/AngularFun#commentary ）

# 商用 WEB アプリケーション開発の際の問題点
さて、開発の際には requireJS はとても便利なソリューションだが、実際に商用の WEB アプリケーションを作る上では通信コストを考慮しなければならない。モジュールごとにファイルを細かく分割しておきたいが、公開の際には、

- ファイル結合
- minify
- gzip 圧縮

して提供したい。

ファイル結合さえ出来てしまえば minify, gzip 圧縮は grunt のタスクとしてそういうのがあるので、あんまし考えることは無い。
問題は、

- 開発ビルド時は「ファイルとファイルリストの組」をもとに main.js を生成
- 商用ビルド時は「ファイルとファイルリストの組」をもとに「結合する順序」を決定

これを、grunt で勝手にやってくれないものだろうか？

# grunt-file-dependency
ざっと探した（あんまり探してない）感じだとよさげなのがなかったので作った↓

https://github.com/amo12937/grunt-file-dependency

こいつを Gruntfile.js に取り込むと、次の2つのタスクが使えるようになる。

- makeMainJs
    - 「ファイルとファイルリストの組」から、main.js を生成する
    - 実際には Gruntfile.js で指定した オブジェクト を、JSON.stringify して require.config にぶち込んだものを出力しているので、shim プロパティに「ファイルとファイルリストの組」を渡した上で、必要に応じて paths, deps などもGruntfile.js から渡す。
- makePriority
    - 「ファイルとファイルリストの組」から、整列されたファイルリスト（配列）を出力する
    - こいつを、concat タスクの src として渡し、同タスクを実行すれば、concat されて出力される。

# Gruntfile.js の例

```js
(function() {
var reqConfig = {
  baseUrl: "scripts/",
  paths: {
    a: "hoge/fuga"
    b: "fizz/buzz"
    // ...
  },
  shim: {
    a: ["b", "c", "d"]
    b: ["c", "e", "f"]
    e: ["g", "h"]
    i: ["a", "b", "e", "j"]
  },
  deps: ["i"]
};

module.exports = function(grunt) {
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-file-dependnecy');
  grunt.initConfig({
    copy: {
      dev: {
        expand: true,
        cwd: "src/scripts/",
        src: "**/*.js",
        dest: "build/dev/scripts/"
      }
    },
    makeMainJs: {
      dev: {
        dest: "build/dev/scripts/main.js",
        main: reqConfig
      }
    },
    makePriority: {
      dist: {
        options: {
          baseUrl: "src/scripts",
          alias: reqConfig.paths
        },
        deps: reqConfig.shim,
        done: function(priority) {
          grunt.config.set("concat.dist.src", priority);
        }
      }
    },
    concat: {
      dist: {
        dest: "vendor/dist/scripts/scripts.js"
      }
    }
  });

  grunt.registerTask("build:dev", ["copy:dev", "makeMainJs:dev"]);
  grunt.registerTask("build:dist", ["makePriority:dist", "concat:dist"]);
};
})();
```

なお readme.md はそのうち書きます。