YEOMANのTutorialをやってみた

# はじめに
[YEOMANのサイトのTutorial](http://yeoman.io/codelab.html)を順にやってみます。  

# 環境
* Max OSX 10.10.2
* node v0.12.0
* npm v2.5.1
* git v2.3.0

# Let's Scaffold a Web App
サンプルWebアプリとして、TODOアプリを作ります。
ドラッグアンドドロップでのTODOの追加、削除、整理、そしてオフライン保存ができるようになります。  

このcodelabが完了するには、約60分かかります。

# Meet Yeoman
Yeomanは、1〜2個のコマンドでWebアプリ全体、またはコントローラやモデルといった個々の部品の定型的なコードを生成します。  

* **[yo](http://yeoman.io/)**:スキャフォールディングツール。
面倒な作業であるフレームワーク固有のscaffoldをジェネレータでやってくれる。

生産性を上げるために、他のツールとも連携します  

* **[grunt](http://gruntjs.com/)** :プロジェクトのビルド、プレビュー、テストで使用。
* **[gulp](http://gulpjs.com/)**：設定よりもコードを好むGrunt JSの代替ツール。
* **[bower](http://bower.io/)**：フロントエンドライブラリの依存を解決するために使用。

# Step 1：開発環境のセットアップ

## インストール前提条件
インストールされていないならインストールしておく。

* Node.js v0.10.x以上
* npm v2.1.0以上 (Nodeに同梱)
* git

## Yeomanツールセットのインストール

```zsh:
$ npm install --global yo bower grunt-cli
```

インストール先のディレクトリにアクセス権限がない（EACCES）とのエラーが出る。
suつけて実行したくなるが、回避策でsuを使用したらダメって書いてあるので、
[このページ](https://github.com/sindresorhus/guides/blob/master/npm-global-without-sudo.md)にしたがって直す。

.zshrcに以下を追記する。

```zsh:~/.zshrc
NPM_PACKAGES="${HOME}/.npm-packages"

NODE_PATH="$NPM_PACKAGES/lib/node_modules:$NODE_PATH"

PATH="$NPM_PACKAGES/bin:$PATH"

# Unset manpath so we can inherit from /etc/manpath via the `manpath`
# command
unset MANPATH # delete if you already modified MANPATH elsewhere in your config
MANPATH="$NPM_PACKAGES/share/man:$(manpath)"
```

~/.npmrcファイルを作成する
```
prefix=${HOME}/.npm-packages
```

```zsh:
$ mkdir "${HOME}/.npm-packages"
$ source ~/.zshrc
```

再度、`npm install --global yo bower grunt-cli`を実行。

## インストール確認
```zsh
$ yo --version && bower --version && grunt --version
```

# Step 2：Yeomanジェネレータのインストール

従来のWeb開発のワークフローでは、典型的なコードの組み立て、依存関係のダウンロード、手動でのWebフォルダ構造の作成に多くの時間が必要でした。  

Yoemanジェネレータがこれを救ってくれます。  
AngularJSプロジェクト用のジェネレータをインストールしましょう！

## AngularJSジェネレータのインストール
```zsh
$ npm install --global generator-angular@0.9.2
```

`npm install`を直接使うのに加えて、Yeoman対話メニューからジェネレータを検索することもできます。
`yo`を実行して、**Install a generator**を選択します。

# Step 3：scaffoldするためにジェネレータを使用
Yeomanでscaffoldingという単語の意味は、具体的な構成要求に基づいてWebアプリ用のファイルを生成することです。

## プロジェクトのフォルダ作成
mytodoフォルダを作成

```zsh:
$ mkdir mytodo && cd mytodo
```

このフォルダがスキャフォールディングされたファイルの配置場所になります。

追加のおまけとして、Angularジェネレータはアプリの名前空間を作成するために、
フォルダの名前を動的に使います。
例えば、mytodoなら**angular.module('mytodoApp', [])**になります。  
次に進む前にタイプミスがないことを確認してください。

## Yeomanメニューからジェネレータへのアクセス
yoを実行。

```zsh:
$ yo
```

以下の画面が出た。Yでもnでもお好きな方で。
```
? ==========================================================================
We're constantly looking for ways to make yo better!
May we anonymously report usage statistics to improve the tool over time?
More info: https://github.com/yeoman/insight & http://yeoman.io
========================================================================== (Y/n)
```

Run a generatorの**Angular**を選択し、Enter。
```
? 'Allo Kazuya! What would you like to do?
  Run a generator
❯ Angular
  Karma
  ──────────────
  Update your generators
  Install a generator
  Find some help
  Get me out of here!
  ──────────────
```

Saasは**n**、Bootstrapは、**Y**、moduleの選択はそのままEnter。
```
? Would you like to use Sass (with Compass)? No
? Would you like to include Bootstrap? Yes
? Which modules would you like to include? (Press <space> to select)
❯◉ angular-animate.js
 ◉ angular-cookies.js
 ◉ angular-resource.js
 ◉ angular-route.js
 ◉ angular-sanitize.js
 ◉ angular-touch.js
```

bowerの自動レポート使用選択画面が出た。Yでもnでもお好きな方で。
```
[?] May bower anonymously report usage statistics to improve the tool over time?
```

Yeomanは、Webアプリの依存関係を見つけるとワークフローのための便利なGruntタスクで取ってきて自動でScaffoldします。


## ジェネレータの設定
いくつかのジェネレータは開発環境の初期設定をスピードアップするために、共通の開発ライブラリをカスタマイズするオプション設定を提供しています。（さっきやったSaasとかBoostrap選択のこと。）

AngularJSのジェネレータは、Sass（Commpass含む）を使用するか、Twitter Bootstrapを含めるかのオプションを提供します。

# Step 4：Yeomanが生成したアプリのレビュー
実際にscaffoldされたものを見るために、mytodoディレクトリを開きます。

```
┣ app：Webアプリの親ディレクトリ  
┃　┣ index.html：Angularアプリの基礎のhtmlファイル  
┃　┣ 404.html, favicon.ico, robots.txt：一般的に使われるWebファイル  
┃　┣ scripts：JSファイル  
┃　┃　　┣ app.js：メインのAngularアプリコード  
┃　┃　　┗ controllers：Angularコントローラ  
┃　┣ styles：CSSファイル  
┃　┗ views：Angularテンプレートの格納場所  
┣ bower_components, bower.json：bowerでインストールされるJavaScript/webの依存関係  
┣ Gruntfile.js, package.json, node_modules：Gruntタスクで必要な設定と依存関係  
┗ test：scaffoldされた、コントローラ用の典型的なテストを含むプロジェクト用のテストランナーとユニットテスト  
```

# Step 5：ブラウザでアプリのプレビュー
Yeomanの機能の一部だから、プレビューのためにローカルWebサーバに特別な設定をする必要はないよ。

## サーバの開始

以下のコマンドを実行すると、[localhost:9000](http://localhost:9000/#/) に
Nodeベースのhttpサーバが立ち上がり・・・

```
$ grunt serve
```

ませんでした。エラー。。。

```
Warning: ENOENT, no such file or directory '/省略/mytodo/app/bower.json' Use --force to continue.
```

[stackoverflow](http://stackoverflow.com/questions/25709324/grunt-wiredepapp-no-such-file-or-directory-bower-json)にしたがって、Gruntfile.js のcwdプロパティをコメントアウトします。

```javascript:変更前Gruntfile.js
// Automatically inject Bower components into the app
164     wiredep: {
165       options: {
166         cwd: '<%= yeoman.app %>'
167       },
168       app: {
169         src: ['<%= yeoman.app %>/index.html'],
170         ignorePath:  /\.\.\//
171       }
172     },
```

```javascript:変更後Gruntfile.js
// Automatically inject Bower components into the app
164     wiredep: {
165       options: {
166         //cwd: '<%= yeoman.app %>'
167       },
168       app: {
169         src: ['<%= yeoman.app %>/index.html'],
170         ignorePath:  /\.\.\//
171       }
172     },
```

再度 `grunt serve` を実行すると、無事にアプリが立ち上がりました。

## サーバの停止
Ctrl + C で停止。

## ファイルの監視
テキストエディタでファイルを変更して保存すると、あなたが何もしなくても、
自動で強制的にブラウザがリフレッシュされます。
これはlive reloadingと呼ばれ、Gruntfile.jsのGruntタスクで設定されています。

# Step 6 AngularJSアプリを書き始める
このセクションのすべての手順は、appフォルダ内のファイルを編集している想定になっています。

## todoリストを表示する新規テンプレートの作成
コードは省略するので、[公式サイト](http://yeoman.io/codelab/write-app.html)を確認して下さい。

**views/main.html**
divの"jumbotron"クラスを"container"クラスに置換する。

**scripts/controllers/main.js**
\$scope.awesomeThings を $scope.todos の配列に変える。

**views/main.html**
todoの項目をHTMLのinputフィールドで出力するためにソースを直す。


* ng-repeat属性
コレクションからアイテムごとにテンプレートをインスタンス化するAngularディレクティブ

* ng-model属性
input、select、textarea、カスタムディレクティブで動作する、
双方向データバインディングを作成するAngularディレクティブ

## todoの追加

**views/main.html**
&lt;h2&gt;と&lt;p&gt;の間にフォームを追加する

**scripts/controllers/main.js**
addTodo()を実装し、ng-submitに結びつける。

これでタスクの追加ができるようになった。
_でも空のtodoを入れるとエラーで止まっちゃうよ。_

## todoの削除

**views/main.html**
削除ボタンを追加する。
クラスを"form-group"から"input-group"に変える。

**scripts/controllers/main.js**
removeTodo()を追加し、ng-clickと結びつける。

# Step 7：パッケージのインストールにBowerを使う
リストに順番を追加し、ソート可能にします。
BowerでAngularUI Sortable モジュールとAngularJS ディレクティブコンポーネントをインストールします。

## 現在のパッケージ一覧

myTodoプロジェクトで以下を実行。

```zsh:
$ bower list
```

## パッケージの検索
angular-ui-sortable が利用可能か検索する。

```zsh:
$ bower search angular-ui-sortable
```

## パッケージのインストール
bowerを使って、"angular-ui-sortable"と"jquery-ui"をインストール。

```zsh:
$ bower install --save angular-ui-sortable
$ bower install --save jquery-ui
```

または

```zsh:
$ bower install --save angular-ui-sortable jquery-ui
```

--save オプションをつけると、bower.jsonに"angular-ui-sortable"と"jquery-ui"の依存関係を更新します。

## インストールの確認
**bower_components**の中に"angular-ui-sortable"と"jquery-ui"があることを確認する。

## todoをソート可能にする
新しくインストールされた依存関係への参照をindex.htmlファイルに追加しなくてはなりません。
手動でもできるけど、Yeomanが自動でやってくれます！  

Ctrl + C でコマンドラインプロセスを終了する。そして再度`grunt serve`を実行する。  

index.html下部のscriptセクションに"jquery-ui/ui/jquery-ui.js"と"angular-ui-sortable/sortable.js"が追加されたのが確認できます。

Sortableモジュールを利用するために、scripts/app.jsのAngularモジュール定義を更新します。　　

ui.sortable を追加します。

**views/main.html**
&lt;div&gt;にui-sortableディレクティブを追加


# Step 8
## KarmaとJasmineでのテスト
KarmaはフレームワークにとらわれないJavaScriptテストランナーです。
AngularジェネレータはngScenarioとJasmineの２つのテストフレームワークが含まれています。

`yo angular`を実行した最初の時に、プロジェクトのルートディレクトリにtestフォルダが作られて、karma.conf.jsが作られて、KarmaのNodeモジュールが持って来られました。

## ユニットテストの実行
Ctrl+C で Gruntサーバを止めます。
テスト実行のためのGruntタスクがすでにGruntfile.js の中にscaffoldされています。

`grunt test`を実行すると、Yeomanコンソールでいくつかの警告が出ます。
心配しないで、今は2つの理由で失敗しているのでこれは期待通りの動きです。

## Karma設定の更新
Step 7でインストールした新しいBowerのコンポーネントを読み込むために、Karmaの設定を更新します。


```javascript:karma.conf.js
files: [
  'bower_components/angular/angular.js',
  'bower_components/angular-mocks/angular-mocks.js',
  'bower_components/angular-animate/angular-animate.js',
  'bower_components/angular-cookies/angular-cookies.js',
  'bower_components/angular-resource/angular-resource.js',
  'bower_components/angular-route/angular-route.js',
  'bower_components/angular-sanitize/angular-sanitize.js',
  'bower_components/angular-touch/angular-touch.js',
  'bower_components/jquery/dist/jquery.js',
  'bower_components/jquery-ui/jquery-ui.js',
  'bower_components/angular-ui-sortable/sortable.js',
  'app/scripts/**/*.js',
  'test/mock/**/*.js',
  'test/spec/**/*.js'
],
```

## 単体テストの更新
test/spec/controllers/main.js を開く。
これがAngular MainCtrolコントローラの単体テストです。

**test/spec/controllers/main.js**
awesomeThingsになったままなので、修正する。

**scripts/controllers/main.js**
$scope.todos の3つの要素を削除する。

`grunt test`を再実行すると、テストがOKになる。

## 単体テストをもっと追加
**test/spec/controllers/main.js**
テストを追加する

`grunt test`を再実行すると、テストが4つOKになるのが期待されます。


# Step 9：製品版のための準備

## 製品版のためのファイル最適化
アプリケーションの製品版を作るために以下のことをします。

* コードのlint
* テスト実行
* ネットワークリクエストを節約するために、スクリプトとスタイルの結合と最小化
* 画像を使っているなら最適化
* 使用しているプリプロセッサのアウトプットをコンパイル
* 一般的にアプリをほんとにleanの状態にする

驚くことに、次のコマンドを実行するだけで全部達成できます。
```
$ grunt
```

プロジェクトのルートのdistフォルダの中に、製品準備版のアプリが使用可能な状態で配置されました。

## 製品準備版のビルドとプレビュー
製品アプリをローカルでプレビューしたいなら、他のシンプルなgruntコマンドを実行するだけです。

```
$ grunt serve:dist
```

プロジェクトをビルドして、ローカルサーバで立ち上げてくれます。

# Step 10：ローカルストレージを用いたtodoの永続化
ブラウザがリフレッシュされた時に、項目が永続化されていない問題を再検討します

## Bowerパッケージのインストール
"angular-local-storage"と呼ばれるAngularモジュールを使用すると、簡単にローカルストレージが実装できます。

```
$ bower install --save angular-local-storage
```

## ローカルストレージの追加
Ctrl+Cで現在のコマンドラインプロセスを止めて、`grunt serve`を再実行。
index.htmlの(&lt;!-- bower:js --&gt;部分の)一番下にangular-local-storageを追加されている。

**scripts/app.js**にLocalStorageModuleを追加する。

同じ名前の変数を使っている別のアプリから、誤ってtodoを読み込まないように、ローカルストレージ名のプレフィックスで"ls"を使うよう、app.jsの中でローカルストレージサービスプロバイダを設定します。

ローカルストレージサービスの依存関係を宣言するために、コントローラ（main.js）を更新する必要があります。
コールバック関数で、ローカルストレージサービスに2番めの引数を追加します。

静的な配列からtodoを読み込むのではなく、むしろローカルストレージから値を読み込みたいです。そして、$scope.todosの代わりに、ローカルストレージに保存したいです。

\$scope.todosの値の変化を監視するために、angularの\$watchリスナを使います。
もし誰かがtodoを追加または削除したら、\$watchリスナがローカルストレージのtodoデータストアと動機を維持します。

現在の$scope.todos宣言を削除して、書き換えます。

ブラウザをリフレッシュしても値が持続らされるようになりました。

Chrome DevToosのResourceパネルを選択し、左側からローカルストレージを選択することで、データがローカルストレージに永続化されているかどうかを確認できます。