Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save okunokentaro/8bc8068b96ba57b5201167cc9fc17b02 to your computer and use it in GitHub Desktop.
Save okunokentaro/8bc8068b96ba57b5201167cc9fc17b02 to your computer and use it in GitHub Desktop.
npm i angular2してHello World!するところまで
2015/12/02 にQiitaに投稿した記事のアーカイブです
---
【160325追記】この記事はAngular 2 alpha時代に初稿を仕上げ、それ以降は変更にあわせて保守を続けていましたが、そろそろ差が大きくなってきたため[改稿版として別の記事を用意しました。](http://qiita.com/armorik83/items/ae737ab584012a0f5876)今後はそちらをご覧ください。
---
@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](http://browserify.org/)を使いますが、おそらく[webpack](https://webpack.github.io/)でもいけるはず。
Angular 2は[TypeScript](http://www.typescriptlang.org/)でのコーディングを前提に設計されているので、本稿もTypeScriptを使用します。一応ES6 ([Babel](https://babeljs.io/))やES5でも書けるとは言われていますが、私はTypeScriptで書くのが一番書きやすいと感じています。
## 今回の環境
細かなバージョン違いは影響しないと思いますが、npmだけ、2.x系だとチュートリアル通りにいかない可能性があります。
```
$ node -v
v5.5.0
$ npm -v
3.6.0
```
## 公式サイト
- https://angular.io/
- https://github.com/angular/angular
# 開発環境を作る
## 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](https://github.com/systemjs/systemjs)を推奨していますので、そちらを使っても構いません。どちらを使っても実装自体の`import/export`の書き方が変わるわけではありません。
`package.json`の`"scripts"`を次のように書き換えます。
```package.json
{
"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以降](http://qiita.com/vvakame/items/9b9fde6c71aae6a824c0))は`tsconfig.json`がサポートされていますので、`-p`オプションでプロジェクト・ディレクトリを指定し`tsconfig.json`を使っていくのが標準的な形式です。今回はサンプルなので雑にルートを指定しています。
従来通りコンパイラオプションを書くことも出来ますが、Angular 2の場合は有効にすべきオプションが多いため、積極的に`tsconfig.json`を作成するほうがよいでしょう。オプションについては後述します。
`browserify`は単純にエントリーソースを指定して`bundle.js`として出すだけ。`build`でその二つの処理をまとめています。これくらいの量だと[gulp](http://gulpjs.com/)は使っていません。
## tsconfig.json
```tsconfig.json
{
"compilerOptions": {
"target": "es6",
"noImplicitAny": true,
"removeComments": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"moduleResolution": "node"
},
"files": [
"./index.ts"
]
}
```
`experimentalDecorators`は[Decorators構文](https://speakerdeck.com/armorik83/es7-decorators)を有効にするためのオプションで、`emitDecoratorMetadata`は引数の型アノテーションを実装内でも扱うための出力を指定します。Angular 2のDIのためにあるようなオプションだと認識しています。
それ以外のオプションについては[公式のWiki](https://github.com/Microsoft/TypeScript/wiki/Compiler-Options)を参照してください。`files`はコンパイル対象のファイルを配列で与えますが、これを毎回手書きするのはとても煩雑なので、IDEの支援や[CLI](https://www.npmjs.com/package/tsconfig-cli)を活用して、人の手では書かないようにしましょう。
# ファイル作成
- `index.ts`
- `index.html`
この二つを作成します。
```ts:index.ts
// まだ何もない
```
```html: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しておくとよいでしょう。
```ts:index.ts
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定義
```ts:index.ts
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の定義オブジェクトのようなものです。
```js
angular.module("myapp").directive("myDirective", function() {
return {
restrict: "E",
link: function() {
// ...
}
}; // この辺に似てる
});
```
`selector`はセレクタ、ここではComponent名を表します。~~Angular 2の独自パーサのおかげでここをキャメルケースで記述することも可能になり、HTML中では`<foo-bar></foo-bar>`や`<FooBar></FooBar>`のように書きます。~~ [W3Cの仕様](http://www.w3.org/TR/custom-elements/#concepts)には従うべきなので、要素名は小文字のハイフンで表記すべきです。
`template`は見ての通りテンプレートHTML、ここは`templateUrl`とすることで外部ファイルのパスを指定できます。
`directives`に与える配列は「このComponentが扱う子DirectiveおよびComponent」を含むものです。`directives: [CORE_DIRECTIVES]`とすると十徳ナイフのようにAngular 2の便利DirectiveがまとめてDIできます。(これについては別の機会に)
## 子Componentを作る
Hello Worldを出力するComponentを作ってみましょう。前述の`MyApp`に書いてしまうこともできますが、せっかくなので親子構造をとってみます。
```ts:index.ts
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`を記述します。
```ts:index.ts
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側も追記します。
```html:index.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が出力したソースを指定します。
# ビルド、そして起動
まずは完成形ソースを貼っておきます。
```ts:index.ts
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);
```
```index.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>
```
`npm`でビルドスクリプトを起動し、コンパイル&ビルドしましょう。
```
npm run build
```
少し待つと`bundle.js`が出力されます。あとは`index.html`をブラウザで開けば完了!(まだローカル経由で動きますがRouterやAjaxなどが絡むときはサーバを立ててください)
![Screen Shot 2015-12-01 at 01.28.16.png](https://qiita-image-store.s3.amazonaws.com/0/17959/e7e96c9a-644c-af85-a6d7-19843812d055.png)
まだまだアプリケーションからは程遠いですが、基本的にいくつものComponentを細かく作ってはViewを組み立てていき、その後ろをドメイン層やストア層が支えるというアーキテクチャは変わりません。今回は基礎としてComponentの作り方を紹介しました。Angular 2での本格的なアプリケーション開発については今後の記事・解説などをお待ち下さい。何よりまだalpha版ですからね!
# 実はもっと簡単にできる
ここに[Plunker](http://plnkr.co/edit/?p=catalogue)があるじゃろ?
![Screen Shot 2015-12-01 at 01.32.19.png](https://qiita-image-store.s3.amazonaws.com/0/17959/f2e45899-1052-5455-1da0-9c81711c9cc0.png)
これをこうして、
![Screen Shot 2015-12-01 at 01.32.39.png](https://qiita-image-store.s3.amazonaws.com/0/17959/97031609-09ab-1001-0ed2-bf93ab2575d3.png)
こうじゃ。 ( ^ω^)
---
Plunkerだとビルドも何も要らないのですげー簡単。みんな、これやろう。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment