npm i angular2してHello World!するところまで
【160325 追記】この記事は Angular 2 alpha 時代に初稿を仕上げ、それ以降は変更にあわせて保守を続けていましたが、そろそろ差が大きくなってきたため改稿版として別の記事を用意しました。今後はそちらをご覧ください。
@armorik83 です。初日である昨日は、このアドベントカレンダー最大のサプライズとして@btford 氏に寄稿していただきました。アドベントカレンダーの立ち上げ直後からオファーし、日本の「アドベントカレンダー」という特殊な Tech 系の事情を説明し、Angular 2 のカレンダーをぜひ飾ってほしいという旨で依頼したことを覚えています。直前になって、時差で向こうはまだ 11 月なため日本のカレンダー開始に気付いていなかった、という笑い話も乗り越え、公開にこぎ着けたことを喜ばしく思います。
Thank you so much for contributing!
Angular 2 Advent Calendar 2015 の 2 日目の本日は、皆さんに手っ取り早く Angular 2 を触ってもらうために、npm i
してから Hello World を表示するところまでを解説します。
【151225 追記】本稿公開以降に Angular 2 の alpha バージョンが上がり、公開当初の内容では動かなくなってしまいました。現在は改稿し beta.0 に対応しています。
【160303 追記】現在は改稿し beta.8 に対応しています。
前提知識
npm
を用いたインストール、package.json
での管理には慣れているものとします。今回はビルドにBrowserifyを使いますが、おそらくwebpackでもいけるはず。
Angular 2 はTypeScriptでのコーディングを前提に設計されているので、本稿も TypeScript を使用します。一応 ES6 (Babel)や ES5 でも書けるとは言われていますが、私は TypeScript で書くのが一番書きやすいと感じています。
今回の環境
細かなバージョン違いは影響しないと思いますが、npm だけ、2.x 系だとチュートリアル通りにいかない可能性があります。
$ node -v
v5.5.0
$ npm -v
3.6.0
公式サイト
開発環境を作る
sandbox
Angular 2 をインストールするディレクトリを作成します。これはなんでもかまいません。
mkdir ~/Desktop/angular2-sandbox && $_
インストール
下地となるpackage.json
を作成します。ビルドの際にnpm run
するためにこれが必要です。
npm init -y
続いてインストールを進めていきます。
npm i -D typescript browserify babelify
npm i -S angular2 es6-promise es6-shim@^0.33.3 reflect-metadata@0.1.2 rxjs@5.0.0-beta.2 zone.js@0.5.15
npm i -S angular2
は本体のインストールです。npm 2 系ではnpm i -S reflect-metadata zone.js
が必要かもしれません。これも将来的には不要になる(Angular 2 が内部で依存するようになる)見込みのようです。
Angular 2 beta.8 時点では es6-promise 以下のモジュールも手動で指定してインストールする必要があり、それを満たさない場合 npm はUNMET PEER DEPENDENCY
と警告を出します。今後 beta.2 以降で上記を試した時にもしUNMET PEER DEPENDENCY
と表示されたらバージョン指定がズレている可能性があるので、エラー文を頼りに修正してください。
TypeScript の-t es6
が指定できるにも関わらずes6-promise es6-shim
が必須と指定されていますが、今後この辺りは整理されると予想しています。
ビルドスクリプト
TypeScript で書くためコンパイルが必要です。それぞれのファイルは TypeScript のimport/export
によって依存関係を記述するので、最終的には Browserify を使用します。
Angular 2 公式のチュートリアルでは Browserify ではなくSystemJSを推奨していますので、そちらを使っても構いません。どちらを使っても実装自体のimport/export
の書き方が変わるわけではありません。
package.json
の"scripts"
を次のように書き換えます。
{
"scripts": {
"tsc": "tsc -p ./",
"browserify": "browserify ./index.js -t babelify -o ./bundle.js",
"build": "npm run tsc && npm run browserify"
},
"babel": {
"presets": ["es2015"]
},
}
tsc
では、-t es5 -m commonjs
とオプションを渡すのが初期のバージョンでおなじみでしたが、現在(TypeScript 1.5.3 以降)はtsconfig.json
がサポートされていますので、-p
オプションでプロジェクト・ディレクトリを指定しtsconfig.json
を使っていくのが標準的な形式です。今回はサンプルなので雑にルートを指定しています。
従来通りコンパイラオプションを書くことも出来ますが、Angular 2 の場合は有効にすべきオプションが多いため、積極的にtsconfig.json
を作成するほうがよいでしょう。オプションについては後述します。
browserify
は単純にエントリーソースを指定してbundle.js
として出すだけ。build
でその二つの処理をまとめています。これくらいの量だとgulpは使っていません。
tsconfig.json
{
"compilerOptions": {
"target": "es6",
"noImplicitAny": true,
"removeComments": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"moduleResolution": "node"
},
"files": [
"./index.ts"
]
}
experimentalDecorators
はDecorators 構文を有効にするためのオプションで、emitDecoratorMetadata
は引数の型アノテーションを実装内でも扱うための出力を指定します。Angular 2 の DI のためにあるようなオプションだと認識しています。
それ以外のオプションについては公式の Wikiを参照してください。files
はコンパイル対象のファイルを配列で与えますが、これを毎回手書きするのはとても煩雑なので、IDE の支援やCLIを活用して、人の手では書かないようにしましょう。
ファイル作成
index.ts
index.html
この二つを作成します。
// まだ何もない
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Angular 2 Advent Calendar 2015</title>
</head>
<body>
</body>
</html>
コーディング
Angular 2 を import
"angular2/*"
から Angular 2 の様々な API を取得できます。今回は初回起動に必要なbootstrap
とコンポーネント定義に使うComponent
を import します。CORE_DIRECTIVES
は今回は扱いませんが、Angular 2 の標準的な Directive が詰まったパッケージなので、import しておくとよいでしょう。
import "reflect-metadata";
import "zone.js";
import "rxjs/Rx";
import {bootstrap} from "angular2/platform/browser";
import {Component} from "angular2/core";
import {CORE_DIRECTIVES} from "angular2/common";
このとき、beta.8 時点ではreflect-metadata
, zone.js
, rxjs/Rx
の import も必要となります。
Component 定義
import "reflect-metadata";
import "zone.js";
import "rxjs/Rx";
import {bootstrap} from "angular2/platform/browser";
import {Component} from "angular2/core";
import {CORE_DIRECTIVES} from "angular2/common";
@Component({
selector: `my-app`,
template: `
<hello-world></hello-world>
`,
directives: [CORE_DIRECTIVES]
})
class MyApp {
}
今回は MyApp という Component を作るとします。class MyApp {}
と書いた上に@Component()
の Decorators を添えます。
class
構文は JavaScript の印象と異なるかもしれませんが、JavaScript (ECMAScript)の次版である ES6 や TypeScript で、もはやお馴染みな構文です。一方で@
を冠する Decorators 構文は ECMAScript には策定されておらず(proposal 審議中)TypeScript の仕様には含まれている構文です。これを本格的に扱うのは Angular 2 が初ではないでしょうか。
@Component
の引数オブジェクトは、AngularJS でいう Directive の定義オブジェクトのようなものです。
angular.module("myapp").directive("myDirective", function () {
return {
restrict: "E",
link: function () {
// ...
},
}; // この辺に似てる
});
selector
はセレクタ、ここでは Component 名を表します。Angular 2 の独自パーサのおかげでここをキャメルケースで記述することも可能になり、HTML 中では W3C の仕様には従うべきなので、要素名は小文字のハイフンで表記すべきです。<foo-bar></foo-bar>
や<FooBar></FooBar>
のように書きます。
template
は見ての通りテンプレート HTML、ここはtemplateUrl
とすることで外部ファイルのパスを指定できます。
directives
に与える配列は「この Component が扱う子 Directive および Component」を含むものです。directives: [CORE_DIRECTIVES]
とすると十徳ナイフのように Angular 2 の便利 Directive がまとめて DI できます。(これについては別の機会に)
子 Component を作る
Hello World を出力する Component を作ってみましょう。前述のMyApp
に書いてしまうこともできますが、せっかくなので親子構造をとってみます。
import "reflect-metadata";
import "zone.js";
import "rxjs/Rx";
import {bootstrap} from "angular2/platform/browser";
import {Component} from "angular2/core";
import {CORE_DIRECTIVES} from "angular2/common";
@Component({
selector: `hello-world`,
template: `
<h1>Hello World!</h1>
`
})
class HelloWorld {
}
@Component({
selector: `my-app`,
template: `
<hello-world></hello-world>
`,
directives: [CORE_DIRECTIVES, HelloWorld]
})
class MyApp {
}
このように、Angular 2 では Component を複数記述するのも簡単です。MyApp
のdirectives
配列にHelloWorld
を追加している点に注意してください。
ここでは一つのファイルにまとめていますが、実際のアプリケーション開発ではもちろん複数のファイルに分割し、互いにimport/export
してください。
エントリーポイントを記述
最後にエントリーポイントであるbootstrap
を記述します。
import "reflect-metadata";
import "zone.js";
import "rxjs/Rx";
import {bootstrap} from "angular2/platform/browser";
import {Component} from "angular2/core";
import {CORE_DIRECTIVES} from "angular2/common";
// 略
@Component({
// ...
})
class MyApp {
}
bootstrap(MyApp);
bootstrap は、最初に表示される HTML と Angular 2 を繋ぐ大切な処理です。この引数に与える Component class は、Angular 2 アプリケーションのルートとなる Component です。HTML 側も追記します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Angular 2 Advent Calendar 2015</title>
</head>
<body>
<my-app>Loading…</my-app>
<script src="./bundle.js"></script>
</body>
</html>
<my-app>
内は読み込み後にテンプレートに置き換わりますが、ローディング表示を書くことも可能です。その下、<script src="">
では Browserify が出力したソースを指定します。
ビルド、そして起動
まずは完成形ソースを貼っておきます。
import "reflect-metadata";
import "zone.js";
import "rxjs/Rx";
import {bootstrap} from "angular2/platform/browser";
import {Component} from "angular2/core";
import {CORE_DIRECTIVES} from "angular2/common";
@Component({
selector: `hello-world`,
template: `
<h1>Hello World!</h1>
`
})
class HelloWorld {
}
@Component({
selector: `my-app`,
template: `
<hello-world></hello-world>
`,
directives: [CORE_DIRECTIVES, HelloWorld]
})
class MyApp {
}
bootstrap(MyApp);
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Angular 2 Advent Calendar 2015</title>
</head>
<body>
<my-app>Loading…</my-app>
<script src="./bundle.js"></script>
</body>
</html>
npm
でビルドスクリプトを起動し、コンパイル&ビルドしましょう。
npm run build
少し待つとbundle.js
が出力されます。あとはindex.html
をブラウザで開けば完了!(まだローカル経由で動きますが Router や Ajax などが絡むときはサーバを立ててください)
まだまだアプリケーションからは程遠いですが、基本的にいくつもの Component を細かく作っては View を組み立てていき、その後ろをドメイン層やストア層が支えるというアーキテクチャは変わりません。今回は基礎として Component の作り方を紹介しました。Angular 2 での本格的なアプリケーション開発については今後の記事・解説などをお待ち下さい。何よりまだ alpha 版ですからね!
実はもっと簡単にできる
ここにPlunkerがあるじゃろ?
これをこうして、
こうじゃ。
Plunker だとビルドも何も要らないのですげー簡単。みんな、これやろう。
Discussion