yeomanのangular-generatorで作られたGruntfile.jsはこんな構成になっている


ぶっちゃけ全然分からなかったので読み解いてみた。

## Gruntfile.jsの中身
### use strict
```js:Gruntfile.js
// Generated on 2015-08-27 using generator-angular 0.11.1
'use strict';
```
今までうまいことやってくれてたがためにバグを産んでたところがエラーとみなされるようになった。[参考資料](http://analogic.jp/use-strict/)

### Globbing
```js:Gruntfile.js
// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'
```
対象ディレクトリを再帰的に検索するか直下のものに限定するか。
`{,*/}`は、`{}`内の`,`で区切られたもののどれかに当てはまるディレクトリを検索する。
`'test/spec/{,*/}*.js'`であれば、`'test/spec/*.js'`または`'test/spec/*/*.js'`を検索する。`**`は複数のサブディレクトリの再帰検索を示す。[参考資料](http://stackoverflow.com/questions/19485806/what-does-mean-in-paths-of-gruntfile-js)

### module.exports
```js:Gruntfile.js
module.exports = function (grunt) {
```
Gruntfileの内容はすべてこの中に書く。いや、ほんと何も分からないんですよ…。

### npmモジュールのロード
```js:Gruntfile.js
  // Load grunt tasks automatically
  require('load-grunt-tasks')(grunt);

  // Time how long tasks take. Can help when optimizing build times
  require('time-grunt')(grunt);

  // Configurable paths for the application
  var appConfig = {
    app: require('./bower.json').appPath || 'app',
    dist: 'dist'
  };
```
`load-grunt-tasks`は、ワイルドカードで`grunt.loadNpmTasks`をまとめてくれる。これ自身はデフォルト値を利用して`grunt-*`に一致するすべてのNpmTasksをロードしてくれる。[参考資料](http://qiita.com/makotot/items/b932c3e6a6196d7c0dc2)
`time-grunt`はタスクの実行時間を計測してくれる。[参考資料](http://www.d-wood.com/blog/2014/01/09_5231.html)
appConfigは下で読み込むための値。

### 初期値設定
```js:Gruntfile.js
  // Define the configuration for all the tasks
  grunt.initConfig({
```
この中に初期化処理を書く。

### アプリケーションの設定を読み込み
```js:Gruntfile.js
    // Project settings
    yeoman: appConfig,
```
上記のappConfigを`yeoman`というキー値で読み込む。
以下で`yeoman.app`とか出てきたらこれを参照してるんだと思う。

### grunt-contrib-watchの設定
```js:Gruntfile.js
    // Watches files for changes and runs tasks based on the changed files
    watch: {
      bower: {
        files: ['bower.json'],
        tasks: ['wiredep']
      },
      js: {
        files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
        tasks: ['newer:jshint:all'],
        options: {
          livereload: '<%= connect.options.livereload %>'
        }
      },
      jsTest: {
        files: ['test/spec/{,*/}*.js'],
        tasks: ['newer:jshint:test', 'karma']
      },
      styles: {
        files: ['<%= yeoman.app %>/styles/{,*/}*.css'],
        tasks: ['newer:copy:styles', 'autoprefixer']
      },
      gruntfile: {
        files: ['Gruntfile.js']
      },
      livereload: {
        options: {
          livereload: '<%= connect.options.livereload %>'
        },
        files: [
          '<%= yeoman.app %>/{,*/}*.html',
          '.tmp/styles/{,*/}*.css',
          '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
        ]
      }
    },
```
[grunt-contrib-watch(github)](https://github.com/gruntjs/grunt-contrib-watch)についての設定。(gruntはプラグインと同じ名称のオブジェクトを設定として読み込む。)
このプラグインは名前の通りファイル監視用プラグインで、`files`で指定したディレクトリにファイルの変更があったら察知して`tasks`に指定したタスクを実行する。
`bower`や`js`はターゲットと言って`$grunt watch:bower`というようにコロンつなぎで実行するとこの中に書かれた設定でコマンドが実行される。[Grunt公式サイト](http://gruntjs.com/configuring-tasks#task-configuration-and-targets)参照。
たとえば`bower`なら、

- `files: ['bower.json']` bower.jsonに変更があったら、
- `tasks: ['wiredep']` wiredep(アプリケーションにbowerプラグインを自動で読み込む)タスクを実行する。

### grunt-contrib-connectの設定
```js:Gruntfile.js
    // The actual grunt server settings
    connect: {
      options: {
        port: 9000,
        // Change this to '0.0.0.0' to access the server from outside.
        hostname: 'localhost',
        livereload: 35729
      },
      livereload: {
        options: {
          open: true,
          middleware: function (connect) {
            return [
              connect.static('.tmp'),
              connect().use(
                '/bower_components',
                connect.static('./bower_components')
              ),
              connect().use(
                '/app/styles',
                connect.static('./app/styles')
              ),
              connect.static(appConfig.app)
            ];
          }
        }
      },
      test: {
        options: {
          port: 9001,
          middleware: function (connect) {
            return [
              connect.static('.tmp'),
              connect.static('test'),
              connect().use(
                '/bower_components',
                connect.static('./bower_components')
              ),
              connect.static(appConfig.app)
            ];
          }
        }
      },
      dist: {
        options: {
          open: true,
          base: '<%= yeoman.dist %>'
        }
      }
    },
```
[grunt-contrib-connect(github)](https://github.com/gruntjs/grunt-contrib-connect)について設定。[参考資料](http://www.d-wood.com/blog/2013/11/15_5033.html)
このプラグインはgruntで静的サーバを立ち上げる。
`options`ターゲットは`connect`タスク共通の設定で、特に他のターゲットで上書きしなければこれが適用される。
`options`は、

- `port: 9000,` 9000番ポートを使用し、
- `hostname: 'localhost',` localhostをホストに使用し、
- `livereload: 35729` 変化の自動読み取りには35729番ポートを使用する。

`livereload`では、

- `open: true,` `protocol(デフォルトで'http')`オプション、`hostname`オプション、`port`オプションを合成してデフォルトブラウザで開いてくれる。[openオプション](https://github.com/gruntjs/grunt-contrib-connect#open)参照。
- `middleware: function (connect) {...` **よくわかりません。** なんかサーバに配置するものとか決めてるんですかね…違うだろうな…。

### jshintの設定
```js:Gruntfile.js
    // Make sure code styles are up to par and there are no obvious mistakes
    jshint: {
      options: {
        jshintrc: '.jshintrc',
        reporter: require('jshint-stylish')
      },
      all: {
        src: [
          'Gruntfile.js',
          '<%= yeoman.app %>/scripts/{,*/}*.js'
        ]
      },
      test: {
        options: {
          jshintrc: 'test/.jshintrc'
        },
        src: ['test/spec/{,*/}*.js']
      }
    },
```
[jshint(github)](https://github.com/gruntjs/grunt-contrib-jshint)についての設定。
このプラグインは[JSHint](http://jshint.com/docs/)をgruntから実行できる。
以下、オプションの説明。

- `jshintrc` 特に設定しなければデフォルトの設定が使用される。今回は`'.jshintrc'`を指定している。
- `reporter` 結果のアウトプットを指定しているようだ。今回は外部プラグイン[jshint-stylish](https://github.com/sindresorhus/jshint-stylish)を使用している。
- `src` はそのまま、対象ディレクトリを指定している。ちなみに`<%= yeoman.app %>`は、[公式サンプル](http://gruntjs.com/sample-gruntfile)どおりGruntfileの他の部分で宣言したオブジェクトの値を流用している。

### cleanの設定
```js:Gruntfile.js
    // Empties folders to start fresh
    clean: {
      dist: {
        files: [{
          dot: true,
          src: [
            '.tmp',
            '<%= yeoman.dist %>/{,*/}*',
            '!<%= yeoman.dist %>/.git{,*/}*'
          ]
        }]
      },
      server: '.tmp'
    },
```
[grunt-contrib-clean(github)](https://github.com/gruntjs/grunt-contrib-clean)の設定。
これは指定したディレクトリ内を掃除してくれる。
設定は簡単なので割愛。多分ドットファイルを対象とするかとか対象のディレクトリはどこか、とか決めているのでしょう。(慢心)

### autoprefixerの設定
```js:Gruntfile.js
    // Add vendor prefixed styles
    autoprefixer: {
      options: {
        browsers: ['last 1 version']
      },
      server: {
        options: {
          map: true,
        },
        files: [{
          expand: true,
          cwd: '.tmp/styles/',
          src: '{,*/}*.css',
          dest: '.tmp/styles/'
        }]
      },
      dist: {
        files: [{
          expand: true,
          cwd: '.tmp/styles/',
          src: '{,*/}*.css',
          dest: '.tmp/styles/'
        }]
      }
    },
```
[grunt-autoprefixer(github)](https://github.com/nDmitry/grunt-autoprefixer)の設定。
これはCSSにベンダープレフィックスを自動でつけてくれる。
今回の設定は以下のことを示している。

- `browsers: ['last 1 version']` [browserslist](https://github.com/ai/browserslist)の記法に従って、メジャーなブラウザの最新バージョンを網羅して
- `map: true` source mapっていうのを作成するかどうか選べるみたいですが **よくわかりません**。
- `files` プラグイン依存ではなく、gruntのファイル指定の方法。[公式ドキュメント](http://gruntjs.com/configuring-tasks#files)参照。指定の方法に拡張設定(expand)をすることもできて、それについても[公式ドキュメント](http://gruntjs.com/configuring-tasks#building-the-files-object-dynamically)参照。

### wiredepの設定
```js:Gruntfile.js
    // Automatically inject Bower components into the app
    wiredep: {
      app: {
        src: ['<%= yeoman.app %>/index.html'],
        ignorePath:  /\.\.\//
      },
      test: {
        devDependencies: true,
        src: '<%= karma.unit.configFile %>',
        ignorePath:  /\.\.\//,
        fileTypes:{
          js: {
            block: /(([\s\t]*)\/{2}\s*?bower:\s*?(\S*))(\n|\r|.)*?(\/{2}\s*endbower)/gi,
              detect: {
                js: /'(.*\.js)'/gi
              },
              replace: {
                js: '\'{{filePath}}\','
              }
            }
          }
      }
    },
```
[grunt-wiredep(github)](https://github.com/stephenplusplus/grunt-wiredep)についての設定。
指定したHTMLファイルにbowerコンポーネントを読み込むタグを追記してくれる。
たとえば`app`ターゲットなら

- `src: ['<%= yeoman.app %>/index.html'],` このアプリケーションのindex.htmlに書き込む。
- `ignorePath:  /\.\.\//` ただし`../`は除く。 **実はちょっと意味がわかってません**。

### filerevの設定
```js:Gruntfile.js
    // Renames files for browser caching purposes
    filerev: {
      dist: {
        src: [
          '<%= yeoman.dist %>/scripts/{,*/}*.js',
          '<%= yeoman.dist %>/styles/{,*/}*.css',
          '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
          '<%= yeoman.dist %>/styles/fonts/*'
        ]
      }
    },
```
[filerev(github)](https://github.com/yeoman/grunt-filerev)の設定。
このプラグインはファイルの内容のリビジョンを保管して変更があった時だけキャッシュを更新する。 **ちょっとどんな役割かわかってません。**

### minifiyの設定
```js:Gruntfile.js
    // Reads HTML for usemin blocks to enable smart builds that automatically
    // concat, minify and revision files. Creates configurations in memory so
    // additional tasks can operate on them
    useminPrepare: {
      html: '<%= yeoman.app %>/index.html',
      options: {
        dest: '<%= yeoman.dist %>',
        flow: {
          html: {
            steps: {
              js: ['concat', 'uglifyjs'],
              css: ['cssmin']
            },
            post: {}
          }
        }
      }
    },
    
    // Performs rewrites based on filerev and the useminPrepare configuration
    usemin: {
      html: ['<%= yeoman.dist %>/{,*/}*.html'],
      css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
      options: {
        assetsDirs: [
          '<%= yeoman.dist %>',
          '<%= yeoman.dist %>/images',
          '<%= yeoman.dist %>/styles'
        ]
      }
    },

    // The following *-min tasks will produce minified files in the dist folder
    // By default, your `index.html`'s <!-- Usemin block --> will take care of
    // minification. These next options are pre-configured if you do not wish
    // to use the Usemin blocks.
    // cssmin: {
    //   dist: {
    //     files: {
    //       '<%= yeoman.dist %>/styles/main.css': [
    //         '.tmp/styles/{,*/}*.css'
    //       ]
    //     }
    //   }
    // },
    // uglify: {
    //   dist: {
    //     files: {
    //       '<%= yeoman.dist %>/scripts/scripts.js': [
    //         '<%= yeoman.dist %>/scripts/scripts.js'
    //       ]
    //     }
    //   }
    // },
    // concat: {
    //   dist: {}
    // },

    imagemin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>/images',
          src: '{,*/}*.{png,jpg,jpeg,gif}',
          dest: '<%= yeoman.dist %>/images'
        }]
      }
    },

    svgmin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>/images',
          src: '{,*/}*.svg',
          dest: '<%= yeoman.dist %>/images'
        }]
      }
    },

    htmlmin: {
      dist: {
        options: {
          collapseWhitespace: true,
          conservativeCollapse: true,
          collapseBooleanAttributes: true,
          removeCommentsFromCDATA: true,
          removeOptionalTags: true
        },
        files: [{
          expand: true,
          cwd: '<%= yeoman.dist %>',
          src: ['*.html', 'views/{,*/}*.html'],
          dest: '<%= yeoman.dist %>'
        }]
      }
    },
```
[usemin(github)](https://github.com/yeoman/grunt-usemin)に関する設定。
ファイルの最小化について設定ができるようです。

### ng-anotateの設定
```js:Gruntfile.js
    // ng-annotate tries to make the code safe for minification automatically
    // by using the Angular long form for dependency injection.
    ngAnnotate: {
      dist: {
        files: [{
          expand: true,
          cwd: '.tmp/concat/scripts',
          src: '*.js',
          dest: '.tmp/concat/scripts'
        }]
      }
    },
```
[grunt-ng-annotate(github)](https://github.com/mzgol/grunt-ng-annotate)の設定。
AngularJSは変数名を勝手にminifyされると正常に動かなくなってしまうので、それを安全にしようというプラグイン。

### cdnifyの設定
```js:Gruntfile.js
    // Replace Google CDN references
    cdnify: {
      dist: {
        html: ['<%= yeoman.dist %>/*.html']
      }
    },
```
[cdnify(github)](https://github.com/callumlocke/grunt-cdnify)についての設定。静的ファイルをCDNで取得するように変更する？

### copyの設定
```js:Gruntfile.js
    // Copies remaining files to places other tasks can use
    copy: {
      dist: {
        files: [{
          expand: true,
          dot: true,
          cwd: '<%= yeoman.app %>',
          dest: '<%= yeoman.dist %>',
          src: [
            '*.{ico,png,txt}',
            '.htaccess',
            '*.html',
            'views/{,*/}*.html',
            'images/{,*/}*.{webp}',
            'styles/fonts/{,*/}*.*'
          ]
        }, {
          expand: true,
          cwd: '.tmp/images',
          dest: '<%= yeoman.dist %>/images',
          src: ['generated/*']
        }, {
          expand: true,
          cwd: 'bower_components/bootstrap/dist',
          src: 'fonts/*',
          dest: '<%= yeoman.dist %>'
        }]
      },
      styles: {
        expand: true,
        cwd: '<%= yeoman.app %>/styles',
        dest: '.tmp/styles/',
        src: '{,*/}*.css'
      }
    },
```
[grunt-contrib-copy(github)](https://github.com/gruntjs/grunt-contrib-copy)の設定。他のタスクが使用できるように、指定したファイルをコピーするタスク。ファイルを指定したりする動作はautoprefixerの時とおなじ。

### concurrentの設定
```js:Gruntfile.js
    // Run some tasks in parallel to speed up the build process
    concurrent: {
      server: [
        'copy:styles'
      ],
      test: [
        'copy:styles'
      ],
      dist: [
        'copy:styles',
        'imagemin',
        'svgmin'
      ]
    },
```
[grunt-concurrent(github)](https://github.com/sindresorhus/grunt-concurrent)の設定。
これは処理の重いタスクを並列処理してくれるプラグイン。

### karmaの設定
```js:Gruntfile.js
    // Test settings
    karma: {
      unit: {
        configFile: 'test/karma.conf.js',
        singleRun: true
      }
    }
  });
```
[grunt-karma(github)](https://github.com/karma-runner/grunt-karma)の設定。ちなみに[karma](http://karma-runner.github.io/0.13/index.html)はNodeJS製のテスト実行環境。

### タスクの登録
```js:Gruntfile.js
  grunt.registerTask('serve', 'Compile then start a connect web server', function (target) {
    if (target === 'dist') {
      return grunt.task.run(['build', 'connect:dist:keepalive']);
    }

    grunt.task.run([
      'clean:server',
      'wiredep',
      'concurrent:server',
      'autoprefixer:server',
      'connect:livereload',
      'watch'
    ]);
  });

  grunt.registerTask('server', 'DEPRECATED TASK. Use the "serve" task instead', function (target) {
    grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
    grunt.task.run(['serve:' + target]);
  });

  grunt.registerTask('test', [
    'clean:server',
    'wiredep',
    'concurrent:test',
    'autoprefixer',
    'connect:test',
    'karma'
  ]);

  grunt.registerTask('build', [
    'clean:dist',
    'wiredep',
    'useminPrepare',
    'concurrent:dist',
    'autoprefixer',
    'concat',
    'ngAnnotate',
    'copy:dist',
    'cdnify',
    'cssmin',
    'uglify',
    'filerev',
    'usemin',
    'htmlmin'
  ]);

  grunt.registerTask('default', [
    'newer:jshint',
    'test',
    'build'
  ]);
};
```
gruntでは`grunt.registerTask`と書くことでコマンドから実行するときの名前を自分で設定できる。複数のタスクをまとめたタスク名も設定できて、それを実行すると指定したすべてのタスクを実行してくれる。

## 次は
ひと通りは調べられたけど、まだまだ分からないところがたくさんあるので、折に触れて調べよう。
[karma](http://karma-runner.github.io/0.13/index.html)とか[jasmine](http://jasmine.github.io/)とか、あと[gulp](http://gulpjs.com/)もひと通りは知っておきたいなあ。