npm i して Angualr 2 の Hello World!を書くところまで【改】
追記 160914: rc.7 に対応しました、本題はこちらから。冒頭は終了したイベントの宣伝です。
@armorik83 です。先日は私もng-japanに登壇してきましたが、会場内の Angular 2 熱の高さに興奮を覚えたものです。
さて、私が代表を務めているng-kyotoと ng-japan、GDG 神戸、会場の teratail さん、サイボウズ株式会社さんのご協力によって、来る 4/10 と 4/16 に Angular 2 ハンズオン勉強会を開催いたします。
これは両イベント共に ng-kyoto の代表である私の他、@_likr, @shinsukeimai, @pastelInc オーガナイザらが関わっており、初の Angular 2 ハンズオン東西合同開催と銘打って盛り上げております。さらに ng-japan から強力なバックアップとして@can_i_do_web, @laco0416 にもお手伝い頂いています。
ではなぜこれほど Angular 2 を我々がプッシュするか。やはり、盛り上がってほしいからです!Angular 2 は Angular 1 とは打って変わって Web 標準にとても寄り添ったモダン・フレームワークです。先に Web 標準に沿って発表され一世を風靡した React に対して Angular 1 はお世辞にもモダンとは呼べませんでした。ところが 2 になり、ようやくイマドキらしい普通に選択しうるフレームワークとなったのです。
この辺りの、Angular 2 が如何にモダンかという事情は laco0416 のAngular 2 の失敗しない始め方を一読するのが間違いないでしょう。
本稿は同名の旧記事の改稿版です。先に告知したハンズオンでも Angular 2 の導入はお伝えしていきますが、それとは別に「開発方法は見当がつくけれど最初が面倒くさい」という方も多いことでしょう。そんな方々に Angular 2 を始めてもらえるよう"npm i
するところから"紹介していくのが本稿の目的です。Angular 2 は alpha, beta, rc と進むに連れて、初稿を書いた昨年 12 月からも様々な変化がありました。その差異を毎回の記事修正で補うには大きくなってきたことも、この改稿版を書いた理由です。
始めましょう
前置きが長くなりましたが、始めましょう。npm
を用いたインストールや、package.json
での管理には慣れているものとします。今回はビルドにBrowserify, webpackを使います。両方の始め方を紹介するので、慣れている方はどちらかお好みのもので進めてください。Browserify と webpack のどちらを使えばいいか分からない方は、Node.js の標準のモジュールシステムに互換性のある Browserify を使ってください。
SystemJS を用いた方法は公式のチュートリアルに掲載されているため、この記事では触れません。
Angular 2 はTypeScriptでのコーディングを前提に設計されているので、本稿も TypeScript を使用します。ES2015 や ES5 でも書けますが、私は TypeScript で書くことをお勧めしています。
今回の環境
ビルド周りにしか使わないので、細かなバージョン違いは影響しないと思います。
$ node -v
v6.5.0
$ npm -v
3.10.7
公式サイト
開発環境を作る
sandbox
Angular 2 をインストールするディレクトリを作成します。名前は任意です。ここではangular2-sandbox
とします。
mkdir ~/Desktop/angular2-sandbox && cd $_
インストール
まずpackage.json
を作成します。scripts
に記載した処理をビルドの際にnpm run
で実行するために必要です。
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.21 core-js
npm i -D typescript browserify
webpack 派の方は、npm i -D
に続けて次のように記述しましょう。
npm i -D typescript webpack
@angular
で始まる複数のモジュールが Angular 2 本体です。{}
を用いて複数のモジュールをまとめてインストールすることができます。rxjs
とzone.js
は PEER DEPENDENCY となっており、これらは手動でのインストールが必須となります。面倒ではありますが、これらはブラウザに対しての polyfill という位置付けのため、Angular 2 が依存するライブラリではなくユーザが個々でインストールする形となっています。この設計の顛末はissuesにて確認できます。
core-js
は TypeScript で出力した ES5 ソースの中で ES2015 Promise, Collections を動かすために必要な polyfill です。core-js
を含めずにtsc -t es6
として polyfill を使わずに進めることも可能ですが、そのほかで煩雑な変換が求められるので本稿では割愛します。
ビルドスクリプト
TypeScript 1.8 で書くため、ブラウザで動作する JavaScript にするためのコンパイル作業が必要です。これから作成していく各.ts
ファイルは TypeScript のimport
/export
によって互いの依存関係を記述するので、最終的には Browserify, webpack を使用し結合します。
Angular 2 公式のチュートリアルでは SystemJS を推奨していますので、そちらを使っても構いません。どちらを使っても実装自体のimport
/export
の書き方が変わるわけではありません。
package.json
の"scripts"
を次のように書き換えます。
{
"scripts": {
"tsc": "tsc -p .",
"browserify": "browserify ./index.js -o ./bundle.js",
"build": "npm run tsc && npm run browserify"
}
}
webpack だと次のようになります。
{
"scripts": {
"tsc": "tsc -p .",
"webpack": "webpack ./index.js --output-filename ./bundle.js",
"build": "npm run tsc && npm run webpack"
}
}
TypeScript のコンパイルコマンドtsc
では、-p
オプションでプロジェクト・ディレクトリを指定しtsconfig.json
にコンパイルオプションを記述するのが標準的な形式です。これくらいの量だとgulpは使っていません。
tsconfig.json
tsconfig.json
を作成します。
touch tsconfig.json
{
"compilerOptions": {
"target": "es5",
"noImplicitAny": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"moduleResolution": "node"
},
"filesGlob": [
"./**/*.ts",
"!./**/*.d.ts",
"!./node_modules/**/*",
"./node_modules/typescript/lib/lib.es6.d.ts"
],
"files": [
"./index.ts",
"./node_modules/typescript/lib/lib.es6.d.ts"
]
}
experimentalDecorators
はDecorators 構文を有効にするためのオプションで、emitDecoratorMetadata
は引数の型アノテーションを実装内でも扱うための出力を指定します。Angular 2 の型ベースの DI のためにあるオプションだと認識しています。
それ以外のオプションについては公式の Wikiを参照してください。files
はコンパイル対象のファイルを配列で与えますが、これを毎回手書きするのはとても煩雑なので、IDE の支援やCLIを活用して、人の手では書かないようにしましょう。
なお、現在はベータ版のため本稿では触れていませんが、TypeScript 2.0 からはfiles
の記述法が変わり、IDE の支援や CLI を導入することなく増加する.ts
ファイルに対応できるようになります。この方法については TypeScript 2.0 stable がリリースされたときに改稿する予定です。
HTML の作成
初期ロード時に表示する HTML を記述するindex.html
を作成します。
touch index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Hello Angular 2!</title>
</head>
<body>
</body>
</html>
コーディング
エントリポイントとなるindex.ts
、NgModule
(後述)を宣言するapp.module.ts
、Component を記述するapp.component.ts
を作成します。
touch index.ts app.module.ts app.component.ts
index.ts に polyfill を import する
エントリポイントには、まず polyfill の import 文も記述しておく必要があります。まずはここまでです。
import 'core-js';
import 'zone.js/dist/zone';
NgModule を宣言
Angular 2 では、アプリケーションを開発していく際に、まずNgModule
という単位で class を宣言し、そこにアプリケーション内で用いるコンポーネントやサービスを登録していくという流れで進めていきます。また、このNgModule
はライブラリ開発者にとっても、提供するひとつのパッケージの単位として扱うことができます。
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
@NgModule({
imports: [
BrowserModule
],
declarations: [],
bootstrap: []
})
export class AppModule {}
imports
は自分のNgModule
に他のNgModule
を取り込む際に使います。Angular 2 が提供している各種モジュールや、サードパーティのモジュールをここに記述します。今回は Angular 2 のBrowserModule
を使います。
declarations
には、Directive、ComponentやPipeを登録していきます。
bootstrap
には、アプリケーションのエントリポイントとなる Component を指定します。
Component 定義
続いて Angular 2 アプリケーションのルートとなる Component を定義していきます。Component のためには@angular/core
からComponent
を import し、@Component()
としてclass
宣言の直上に記述します。
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: `
<hello-world></hello-world>
`
})
export class AppComponent {}
今回はAppComponent
という Component を作ります。export class AppComponent {}
と書いた上に@Component()
と添えます。これを Decorators 構文といいます。
@
を冠する Decorators 構文は ECMAScript では現在 TC39 Proposal Stage 2、TypeScript では既に使用できる構文です。
@Component()
内の各プロパティを見ていきましょう。selector
はセレクタ、ここでは Component 名を表します。W3Cの仕様に従うべきなので、要素名はキャメルケースにせず小文字のハイフンで表記すべきです。template
は見ての通りテンプレート HTML、ここはプロパティ名をtemplateUrl
とすることで外部ファイルのパスを指定できます。
子 Component を作る
Hello World を出力する Component を作ってみましょう。前述のAppComponent
内に書いてしまうこともできますが、せっかくなので親子構造をとってみます。
touch hello-world.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'hello-world',
template: `
<h1>Hello World!</h1>
`
})
export class HelloWorldComponent {}
このように、Angular 2 では Component を複数記述するのも簡単です。
NgModule に declaration を追加
いま作成した 2 つの Component を、先に作ったNgModule
に登録しましょう。
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { HelloWorldComponent } from './hello-world.component';
@NgModule({
imports: [
BrowserModule
],
declarations: [
AppComponent,
HelloWorldComponent
],
bootstrap: [AppComponent]
})
export class AppModule {}
declarations
に作成した Component を追加していき、bootstrap
にはルートとなる Component のAppComponent
を指定します。
エントリポイントを記述
最後にエントリポイントであるbootstrapModule
を記述します。
import 'core-js';
import 'zone.js/dist/zone';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
bootstrapModule()
の引数に作成したNgModule
を渡します。最後に HTML 側も追記します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Hello Angular 2!</title>
</head>
<body>
<my-app>Loading…</my-app>
<script src="./bundle.js"></script>
</body>
</html>
<my-app>
内は読み込み後にテンプレートに置き換わりますが、ここにローディング表示を書くことも可能です。その下、<script src="">
では Browserify, webpack が出力したソースを指定します。
ビルド、そして起動
npm
でビルドスクリプトを起動し、ビルドしましょう。
npm run build
少し待つとbundle.js
が出力されます。あとはindex.html
をブラウザで開けば完了です!
この例はまだローカル経由で動きますが、Router や Ajax などが絡むときはローカルでサーバを立ててください。
今回の作成の経過はコミット単位でまとめてありますので参考にしてください。
まだまだアプリケーションからは程遠いですが、基本的には、いくつもの Component を細かく作っては View を組み立てていき、その後ろをドメイン層やストア層が支えるというアーキテクチャです。Flux を参考にするのも手でしょう。
今回は公式サイトで紹介されている SystemJS を使わずに Browserify, webpack で Angular 2 を始める方法を説明しました。Angular 2 もいよいよ stable 真近となり毎日開発が進んでいますので、今から小さいアプリ開発にチャレンジして、今後の趣味、業務に活用しましょう!
それではまた。
Discussion