Mainly Devel Notes

Twitter, GitHub, StackOverflow: @ovrmrw (short hand of "overmorrow" that means the day after tomorrow)

Angular2 for TypeScriptの公式チュートリアルを少しアレンジして遊んでみた。

Angular2, TypeScript, System.js

【注】この記事ではAngular2 alpha.47を前提としています。それ以降のバージョンだと色々細かいところで違いがあるので注意してください。

僕は断然TypeScript派であり、それ以外のものを使ってWeb開発とかしたくないのでAngular2がTypeScriptで書かれているというのはとても朗報だし気になってたんですね。
それで何がきっかけか忘れましたが、チュートリアルを発見してやってみたら思いの外楽しくて色々と勉強になったのでメモを残そうと思った次第です。
ちなみに開発環境はWindows7, Visual Studio Codeです。

5 MIN QUICKSTART

今回は上記の公式チュートリアルに沿いつつ少しアレンジする形でプログラムしてみます。

まず適当なフォルダを作り、npmから色々インストールします

npm init -y
npm install angular2@2.0.0-alpha.47 --save --save-exact 
npm install systemjs jquery lodash numeral moment --save
npm install live-server typescript --save-dev

jquery, lodash, numeral, momentは公式チュートリアルには含まれていませんが、とても便利なライブラリなので使いたいですね。


それとTypeScript用定義ファイルを使いたいのでtsdもインストールします。
普段からTypeScriptを書いている人には常識ですね。

npm install -g tsd typescript

tsc, tsdをイニシャライズして、tsconfig.json, tsd.jsonを生成します。

tsc --init
tsd init

tsdを使ってjquery, lodash, numeral, momentのTypeScript用定義ファイルをインストールします。

tsd install jquery lodash numeraljs moment --save

numeralだけここではnumeraljsにしないといけません。不便ですね。しかしそういうものだと思って打ち込むしかありません。

フォルダーを作成します

mkdir src
cd src
mkdir app

フォルダー構成はAngular2公式チュートリアルに倣います。


ここまででインストール等の作業は終わりです。


(root)/tsconfig.json を編集します。

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es5",
    "noImplicitAny": false,
    "sourceMap": false,
    "experimentalDecorators": true,
    "moduleResolution": "node"
  },
  "exclude": [
    "node_modules"
  ]
}

このチュートリアルでは"experimentalDecorators": true"target": "es5"が必須です。
"module": "commonjs"を変更する場合は"moduleResolution": "node"が必須です。後はまあ、好みじゃないですか。


(root)/src/index.html を追加します。

<html>
<head>
  <title>Angular 2 QuickStart</title>
  <script src="../node_modules/systemjs/dist/system.js"></script>
  <script src="../node_modules/angular2/bundles/angular2.dev.js"></script>
  <script src="config.js"></script>
  <script>
    System.import('app/app');
  </script>
</head>
<body>
  <my-app>loading...</my-app>
  <script src="../node_modules/jquery/dist/jquery.min.js"></script>
  <script src="../node_modules/lodash/index.js"></script>
  <script src="../node_modules/moment/min/moment.min.js"></script>
  <script src="../node_modules/numeral/min/numeral.min.js"></script>
</body>
</html>

一部公式のチュートリアルと違っていますが、これで問題なく動きます。System.config()の内容をconfig.jsファイルに書いています。お気に入りのフレームワークであるAurelia.jsがそういう主義なので。


(root)/src/config.js を追加します

System.config({
  baseURL: '.', // (root)/src/がbaseURLとなる。
  packages: {
    'app': { defaultExtension: 'js' }
  }
});

packagesの設定は、(root)/src/app/フォルダの中に同じファイル名で.ts.jsがあった場合、.jsを見に行くよということです。


(root)/src/app/app.ts を追加します

app.tsの中身は公式のチュートリアルを基に色々と書き加えています。
lodash, moment, numeralをインポートしていますね。
windowオブジェクトに枝を生やす系のライブラリはimport文で書くと実行時にエラーを起こすので、HTML内でscriptタグで書くのが無難です。

import {bootstrap, Component} from 'angular2/angular2';
//import * as _ from 'lodash'; // 実行時エラーになるので不採用
//import * as moment from 'moment'; // 実行時エラーになるので不採用
//import * as numeral from 'numeral'; // 実行時エラーになるので不採用

@Component({
  selector: 'my-app',
  template: `
      <h1>My First Angular 2 App</h1>      
      <hr>
      <h2>{{fullName}}</h2>
      <div><input type="text" [(ng-model)]="firstName" /></div>
      <div><input type="text" [(ng-model)]="lastName" /></div>
      <hr>
      <h2>{{formattedNumeralValue}}</h2>
      <div><input type="text" [(ng-model)]="numeralValue" /></div>
      <hr>
      <h2>{{formattedMomentValue}}</h2>
      <div><input type="text" [(ng-model)]="momentValue" /></div>
    `
})
class AppComponent {
  firstName: string = 'T';
  lastName: string = 'N';
  numeralValue: number = 1000000;
  momentValue: string = '2015-11-01';
  get fullName() {
    if (!_.isEmpty(this.firstName) && !_.isEmpty(this.lastName)) {
      return `${this.firstName} ${this.lastName}`;
    } else {
      return 'Input both of name fields.';
    }
  }
  get formattedNumeralValue(){
    return numeral(this.numeralValue).format('0,0.000');
  }
  get formattedMomentValue(){
    return moment(this.momentValue).format('MMMM Do YYYY, h:mm:ss a');
  }
}
bootstrap(AppComponent);

一応いくつか説明します。
1.@ComponentデコレーターによってAppComponentクラスがHTMLとどのように関連付けられるかが決定します。
2.@Componentselectorと同じタグ(<my-app>)をHTML内に見つけてtemplateの内容を埋め込みます。
3.bootstrap()を書かないとHTMLと関連付けされません。


あとは実際に動かしてみるだけです。

(root)/package.json の"scripts"を編集します

{
  "scripts": {
    "tsc": "./node_modules/.bin/tsc -p . -w",
    "start": "live-server --open=src"
  },
}

"live-server --open=src"はWebサーバー(live-server)が"http://127.0.0.1:8080/src/"を開くという意味になります。もし--open=.とすると"http://127.0.0.1:8080/"を開きます。


TypeScriptファイルをコンパイルする場合はこう。

npm run tsc

コマンドプロンプトを閉じなければ変更を監視して繰り返しコンパイルしてくれます。


サーバーを起動する場合はこう。

npm start

勝手にブラウザが起ち上がってページが表示されるはずです。
ファイルが変更されたら自動的にリロードされます。


以上です、ありがとうございました。