Angular2系入門風

*こちらの資料は社内勉強会で発表したものになります

---

# Agenda

- Angular2系について
- 最小スタートするには
- その後のこと

---

# Angular2系について
- `Angular2`ではなく、`Angular`の2系である
- Component指向
    - UIをComponentの組み合わせとして構築しようという考え方
    - Angular2系は画面に表示するためのDOMを記述する際は全てComponentとして書く

---

- 大体全部入り
    - HTMLのComponent作れる
    - HTTPリクエスト飛ばせる
    - データバインドしてくれる
    - 適用範囲を絞った、scopedなCSSを扱える
    - イベント発火やらのデータフローを扱える
    - DIの機構を提供してくれる
    - ルーティング出来る
    - その他も色々出来る（雑

---

# 最小スタートするには
発表時点でのサンプルリポジトリ：https://github.com/sisisin-sandbox/hello-ng2

- *Node.jsが実行できる環境がない方はまず最新版をインストールしておきましょう

---

## ライブラリのインストール

[npm iしてAngular 2のHello World!を書くところまで【改】](http://qiita.com/armorik83/items/ae737ab584012a0f5876)や、[公式のQuickstart](https://angular.io/docs/ts/latest/quickstart.html)を参考にしつつ、Angular2系に必要なパッケージを新たに`npm install`していきます

```
npm init -y
npm i -S @angular/{core,common,compiler,platform-browser,platform-browser-dynamic} rxjs@5.0.0-beta.12 zone.js@0.6.26 core-js
npm i -D typescript @types/{core-js,node} browserify
```

---

# 補足1

- Angularのコアライブラリ群,RxJS,Zone.js,core-jsが必須パッケージ
    - Angular,core-jsは基本最新版でOK
    - 最小構成だとコアライブラリの`forms`や`http`などはなくてもよい
    - RxJS,Zone.jsは公式サイトのQuickstartにあるpackage.jsonのサンプルを確認の上、バージョンをあわせて`npm install`コマンドを実行する

---

# 補足2
- TypeScriptも実質必須
    - 出回ってる情報は基本TypeScriptなので使っておくのが無難

---

# 補足3
- bundlerはbrowserify,webpack,rollup辺りから好みに応じて利用する
- ちょっとためすだけならbrowserifyがおすすめ
    - tree shaking使いたいならwebpack2かrollupを使う
    - プロダクション環境ではAoTコンパイルを使うためにwebpack2系などを推奨
        - ES Modulesが解釈できるbundlerであればよい
        - （こちら @laco0416 さんの指摘より追加しました。ありがとうございます！）
    - 公式のquick startではSystem.js使ってますが回避したほうが無難

(以後話を簡単にするためにbrowserify前提で進めます

---

# 補足4

色々説明しましたが、正直めんどいので何も考えずに最初のコマンド叩いとけばいいです

---

## tsconfigの用意
TypeScriptを使うのでその設定ファイルを用意します

```tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "noImplicitAny": true,
    "outDir": "./tmp"
  },
  "exclude": [
    "node_modules"
  ]
}
```

---

補足

- Angular2系ではDecorator構文を利用するので`emitDecoratorMetadata`,`experimentalDecorators`を`true`にする
- モジュールの記述をCommonJS形式に変換したうえでbundleする必要があるため、`module`を`commonjs`に指定する
- TypeScript使うなら`noImplicitAny`は`true`にしとこう
- 出力先ディレクトリを指定(`tsc`(TypeScriptのトランスパイルのコマンド) -> bundle(browserifyによるファイルの結合)とビルドするための一時的な出力)
- この時点で適当にindex.tsを作成して、`$(npm bin)/tsc`を実行してトランスパイルが通ることを確認しておくといいかも

---

## ビルドスクリプトの記述

`scripts`に下記のようにコマンドを定義します

```package.json
...
  "scripts": {
    "tsc": "tsc",
    "tsc:w": "tsc -w",
    "bundle": "browserify ./tmp/index.js -o ./bundle.js",
    "bundle:w": "watchify ./tmp/index.js -o ./bundle.js -v",
    "build": "npm run tsc && npm run bundle",
    "watch": "npm-run-all --parallel tsc:w bundle:w"
  },
...
```

おもむろにbuildコマンドを叩きます

```bash
$ npm run build
```

---

補足

- npm scriptsで定義したコマンド内では、`node_modules/.bin`にパスが通るので、ここで定義した`tsc`は`node_modules/.bin/tsc`と等価である
- watchコマンドは開発時にファイル変更の自動検知・自動ビルドのために定義
    - 別途`npm i -D watchify npm-run-all`でパッケージをインストールする必要あり

---

# コードを用意する
ここまで来てようやくTypeScriptを書き始めます

最初にファイルを作成しておきます

```
$ mkdir src && touch index.html src/index.ts src/app.module.ts src/app.component.ts
```

---

# 何はともあれHTML

```html:index.html
<html>
<body>
  <my-app>Loading...</my-app>
  <script src="./bundle.js"></script>
</body>
</html>
```

---

補足

- scriptタグでのファイルの読み込みはAngularのComponentになるカスタムエレメント(`my-app`)よりあとにないと動かないので注意
    - これ知っておかないと例えばRailsのSprockets絡みで若干困るかもしれない

---

## Componentを作る

```ts:./src/app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <div>hello world</div>
  `
})
export class AppComponent { }

```

---

補足

- `@angular/core`から`Component`をimportして、`@Component`デコレータを利用できるようにする
    - デコレータは実際はただの関数なので他のモジュール同様にimportして利用する
- `@Component`デコレータで`AppComponent`クラスをAngularのComponentとして定義する
- 振る舞いを定義していないので、ここではAppCopmonentクラスの実装は空のままで良い
- selectorで指定した文字列をHTMLのElementのように記述できる
    - この例では`<my-app></my-app>`のように書く
    - 従って、先程作った`index.html`ではこのComponentを参照している

---

# NgModuleを定義する

NgModuleってなんやねんという話ですが、要は定義したComponent等をAngularに読み込ませる場所です。
ここに記述がないとComponentとして実行できません。
Componentの他に、Service,DirectiveなどのAngularのモジュールとして定義したものについても同様です


---

```ts:./src/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';

@NgModule({
  imports: [BrowserModule],
  declarations: [AppComponent],
  bootstrap: [AppComponent]
})
export class AppModule { }
```

---

補足

- `Component`同様、`@angular/core`から`NgModule`をimportしてデコレータを利用できるようにする
- `imports`で外部のmoduleを取り込む
- `declarations`でComponent,Directiveを取り込む
- `bootstrap`でroot componentを定義
- 以上の定義を持った`NgModule`をもつ`AppModule`を作る。これもまた実装は持たなくて良い

---

# エントリポイントを作成

```ts:index.ts
import 'core-js';
import 'zone.js/dist/zone';

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

platformBrowserDynamic().bootstrapModule(AppModule)
```

---

補足

- Pollyfillである`core-js`,`zone.js`はここで読み込む
- ブラウザ上でAnuglarを実行するための関数に定義したModuleを渡してAngularアプリを起動させる

---

# 画面を表示させる

```
$ npm run build
$ python -m SimpleHTTPServer # お好きなサーバをどうぞ
```

`localhost:8000`にアクセスして無事起動したらめでたしめでたし。

---

# その後のこと

- ng-japanの主催するハンズオン資料(https://github.com/ng-japan/ng2-hands-on-seed/tree/master/courses/tutorial)を一通り触るといいと思います
- `angular-cli`ベースのコードでAngularWayを知ってから好きな構成作れるようになるといいのかも
    - ※自分は触ってないので妄想です
- 公式ドキュメントの[ADVANCED](https://angular.io/docs/ts/latest/guide/ngmodule.html)の項目とか眺めてると割と捗ります
- Fluxやりたい人は[Walts](http://qiita.com/armorik83/items/191d50cbf093778198fe)使うといいと思います（ダイマ

---

# HappyHacking!