Angularの基本構造を理解して、アプリ開発を始めるには?:Angular TIPS
初めてのAngular開発【v4以降対応】。誤解のしようもない最も基本的な“Hello World”を作成して、Angularアプリの基本構造を理解しよう。
※現在では、Web標準技術を利用したアプリ開発が広く普及し、そのためのフレームワークも多数存在しています。その中でも主流のフレームワークの1つである「Angular」を活用し、そのための知識を備えることには大きな意味があります。本連載は、Angularユーザーに向けて、その使いこなしTIPSを紹介するものです。なお、本連載は「Build Insider」で公開していた連載「Angular Tips」を同サイトおよび筆者の了解を得たうえで、本フォーラムに移行したものです。記事はBuild Insiderで公開した状態のまま移行しているため、用語統一などの基準が@ITの通常の記事とは異なる場合があります。
別稿「TIPS:Angularの特徴とは? 開発環境を構築するには?」(以降、準備編)では、Angularとは、に始まり、Angular QuickStart Source(以降、QuickStart)を利用して、Angularアプリの骨格を準備、インストールするまでを済ませました。本稿では、準備編で作成したアプリにあらかじめ用意されているサンプルアプリ(つまりQuickStartに含まれているソースコード)を読み解き、実際に動作させるまでを見ていきます。実践でAngular開発をしていく場合には基本的にQuickStartからスタートすればよく、本稿で説明する【1】〜【4】の作業は不要ですが、本稿では「実際にゼロから開発する場合の流れ・手順」でソースコードを読み解いていきます。
QuickStartで用意されているのは、「Hello Angular」を表示するだけの、ごく基本的なサンプルです(図1)。誤解のしようもない基本的なサンプルなので、「またか」と思わず、Angularアプリの基本的な構造を理解してください。
【1】モジュールを準備する
モジュールとは、アプリを構成するオブジェクト(=コンポーネント)を束ねるための仕組みです。Angularそれ自体も複数のモジュールから構成されており、アプリの要件に応じて必要なモジュールをインポートして利用することになります。
もちろん、モジュールはアプリ開発者が自ら定義することもできます。原則として、Angularアプリは、1つ以上のモジュールから構成されていなければなりません。アプリを起動する際に呼び出されるモジュールのことを、ルートモジュールとも呼びます(いわゆる、アプリのエントリーポイントを内包するメインモジュールです)。
以下に、その具体的なコードを示します(※なお、このコードは/src/appフォルダーに含まれているapp.module.tsファイルです)。
// [1] Angularで利用するモジュールをインポート
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
// 2 AppComponentコンポーネントをインポート
import { AppComponent } from './app.component';
// [4] モジュールに関する情報を宣言
@NgModule({
imports: [ BrowserModule ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
// [3]モジュールクラスを準備
export class AppModule { }
各番号の内容は本文で詳しく説明します。[3]と[4]は順番が逆になっているので注意すること。
まず、import命令で、Angularアプリを動作させるのに必要となるモジュール/コンポーネントをインポートします。
[構文]import命令
import { name, …… } from module
- name: インポートする要素
- module: モジュール
[1]の@angular/〜はAngularが提供する標準モジュールです。最低限、モジュールを定義するためのNgModule、ブラウザー上でアプリを動作させるためのBrowserModuleをインポートしておきましょう*1。
*1 あくまで最小限の構成です。本格的なアプリでは、フォームを扱うためのFormsModule、ルーティング機能を提供するRouterModuleなどをインポートする必要があります。
[2]のAppComponentは、アプリの本体を表すコンポーネントです。後からあらためて説明します。
そして、[3]でAppModuleという名前のルートモジュール(=モジュールクラス)を準備しています。他のモジュールから呼び出す際などには、ここで宣言した名前(AppModule)を利用します。
ただし、これだけではモジュールと見なされません。@NgModuleデコレーターでモジュールとしての情報を宣言しておきましょう([4])。デコレーターは、モジュールやクラスなどの要素に対してメタ情報を付与するための仕組みです。Javaでいうところのアノテーションに相当する仕組み、と考えると、分かりやすいかもしれません。デコレーターには「パラメーター名: 値」のハッシュ形式で、あらかじめ決められたパラメーター情報を指定できます。
@NgModuleデコレーターで利用できるパラメーターには、以下のようなものがあります。
パラメーター名 | 概要 |
---|---|
imports | 現在のモジュールで利用する他のモジュール/コンポーネント |
exports | 現在のモジュールで外部に公開するコンポーネントなど |
declarations | モジュール配下のコンポーネント |
bootstrap | 最初に起動すべき最上位のコンポーネント(=ルートコンポーネント) |
表1 @NgModuleデコレーターの主なパラメーター |
この例であれば、「BrowserModuleを参照して」「ルートコンポーネントとしてAppComponentを含んだ」AppModuleモジュールを定義する、という意味になります。
【2】コンポーネントを準備する
手順【1】で保留にしていたルートコンポーネントを作成します(リスト2)。ルートコンポーネント(もしくはメインコンポーネント)とは、アプリで最初に呼び出される、いわゆるエントリーポイントです。
// [1] コンポーネントで利用しているモジュールをインポート
import { Component } from '@angular/core';
// [3] コンポーネントに関する情報を宣言
@Component({
selector: 'app-root',
template: `<h1>Hello {{name}}</h1>`,
})
// [2] コンポーネントクラスを準備
export class AppComponent {
// [4]ビューに表示するための値を準備
name = 'Angular';
}
各番号の内容は本文で説明します。[3]と[2]は順番が逆になっているので注意すること。
まず、[1]はコンポーネントを定義するために必要となるオブジェクトをインポートしています。
コンポーネントの本体は、[2]です。ここでは、先ほどAppModuleモジュールで指定したAppComponentという名前でコンポーネントクラスを作成しています。モジュールから参照できるよう、exportキーワードで外部に公開していることに注意してください。
ただし、このままではコンポーネントとして動作させることはできません。モジュールのときと同じく、コンポーネントの構成情報を@Componentデコレーターで定義しておきましょう([3])。@Componentデコレーターでは、さまざまなパラメーターを指定できますが、ここで利用しているのは、以下の2個です*2。
パラメーター名 | 概要 |
---|---|
selector | コンポーネントの適用先を表すセレクター式 |
template | コンポーネントに適用するビュー(テンプレート) |
表2 @Componentデコレーターの主なパラメーター |
*2 その他のパラメーターについては、後日別稿で解説の予定です。
この例であれば、「<app-root>要素に対して、『「<h1>Hello {{name}}</h1>」』というテンプレートを適用」するためのAppComponentコンポーネントを定義したことになります。
テンプレートの中の{{……}}はInterpolation(補間)と呼ばれる構文で、主に、コンポーネントクラスで用意されたプロパティ(ここではname。[4])などを反映させるために利用します。Interpolationの詳細は、別稿「TIPS:コンポーネントの値をビューに反映させるには?」も併せて参照してください。
[Note]AngularモジュールとJavaScriptモジュール
Angularで「モジュール」といった場合、2種類の意味がある点に注意してください。一つが、@NgModuleデコレーターによって宣言されたAngularモジュール、そして、もう一つがJavaScript(TypeScript)のモジュールです。
まず、Angularモジュールは、Angularアプリを構成するコンポーネントをはじめ、サービス、ディレクティブなどを束ねる論理的な器です(アプリを特定の機能でまとめるための仕組み、と言ってもよいでしょう)。@NgModuleデコレーターによって宣言し、そのimportsパラメーターによって別のモジュールをインポートします(リスト1の[4])。
そして、JavaScript(TypeScript)のモジュールは、物理的な1つ1つのファイルです。モジュール配下のクラス/関数はexportキーワードによって外部に公開し、import命令によってインポートします(リスト3)。
export class AppComponent { ... }
import { AppComponent } from './app.component';
Angularモジュール/JavaScriptモジュール共に、ひとくくりに「モジュール」と呼ばれるため、混同しやすいのですが、両者は別ものです。注意してください。
【3】スタートアップコードを準備する
ルートモジュールとルートコンポーネントを準備できたところで、これらを起動するためのスタートアップコードを準備します。
// [1]アプリ起動に必要なモジュールをインポート
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
// [2]モジュールを起動
platformBrowserDynamic().bootstrapModule(AppModule);
まず、アプリ起動のために必要なモジュールをインポートします([1])。platformBrowserDynamicはブラウザーでアプリを起動するための関数、AppModuleは自分で作成したルートモジュールです(ルートコンポーネントはAppModule経由でインポートされますので、ここではインポート不要です)。
必要なモジュールをインポートできたら、あとは、platformBrowserDynamic#bootstrapModuleメソッドでモジュールを起動します([2])。
【4】メインページを準備する
最後に、アプリを動作させるためのメインページを用意します。メインページは、(/src/appフォルダーではなく)アプリケーションルート直下(つまり/srcフォルダー)に配置するものとします。
<!DOCTYPE html>
<html>
<head>
<title>Angular QuickStart</title>
<base href="/">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<!--[1]Angularの動作に必要なライブラリをインポート -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<!--[2]SystemJSを起動 -->
<script src="systemjs.config.js"></script>
<script>
System.import('main.js').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<!--[3]ルートコンポーネントを呼び出し-->
<app-root>Loading AppComponent content here ...</app-root>
</body>
</html>
まず、Angularアプリを動作させるためのライブラリをインポートします([1])。shim.min.jsファイルはレガシーなブラウザーのためのポリフィル(=足りない機能の穴埋め)、zone.jsファイルとSystem.src.js(SystemJS)ファイルはAngularの動作に必要となるライブラリです。
[2]ではSystemJSの設定情報(=systemjs.config.js、前回の表1と図1を参照)を読み込むと共に、System.importメソッドで/src/appフォルダー配下のmain.jsを起動しています。catchメソッドはmain.jsを読み込めなかった場合の処理で、ここではエラー情報をログに出力しています。
そして、[3]がルートコンポーネントを表示するための領域です。これによって、先ほど@Componentデコレーターのセレクター指定(selectorパラメーター)に合致した要素(ここでは<app-root>要素)に対して、テンプレート(templateパラメーター)の内容が反映されます。
<app-root>要素配下には、Angularが初期化される前に表示されるよう、一般的にはロード待ちのコンテンツを記載しておきます(コンポーネントが処理された後は、要素配下はテンプレートの内容で置き換えられます)。
【5】アプリを起動する
以上でアプリを起動するための準備は完了です。コマンドプロンプト(Windows)やターミナル(Mac)などを使ってnpm startコマンドを実行してください。これにより、リスト6のように実行されます。
> npm start
……上記コマンドの実行により以下のように出力される……
> angular-quickstart@1.0.0 prestart C:\data\atips
> npm run build
> angular-quickstart@1.0.0 build C:\data\atips
> tsc -p src/
> angular-quickstart@1.0.0 start C:\data\atips
> concurrently "npm run build:watch" "npm run serve"
[0]
[0] > angular-quickstart@1.0.0 build:watch C:\data\atips
[0] > tsc -p src/ -w
[0]
[1]
[1] > angular-quickstart@1.0.0 serve C:\data\atips
[1] > lite-server -c=bs-config.json
[1]
[0] 11:24:09 - Compilation complete. Watching for file changes.
[1] ** browser-sync config **
[1] { injectChanges: false,
[1] files: [ './**/*.{html,htm,css,js}' ],
[1] watchOptions: { ignored: 'node_modules' },
[1] server:
[1] { baseDir: 'src',
[1] middleware: [ [Function], [Function] ],
[1] routes: { '/node_modules': 'node_modules' } } }
[1] [BS] Access URLs:
[1] ------------------------------------
[1] Local: http://localhost:3000
[1] External: http://192.168.1.3:3000
[1] ------------------------------------
[1] UI: http://localhost:3001
[1] UI External: http://192.168.1.3:3001
[1] ------------------------------------
[1] [BS] Serving files from: src
[1] [BS] Watching files...
[1] 17.05.09 11:24:14 200 GET /index.html
[1] 17.05.09 11:24:14 200 GET /styles.css
...後略...
これによって、TypeScriptスクリプト(.tsファイル)がコンパイルされると共に、Angular標準の開発用サーバー(lite-server)が起動して、以下のようにアプリが表示されます。この状態で、ソースコード(例えばindex.htmlファイル)を書き換えると、自動的にこれを認識して、ページがリロードされることも確認してみましょう。
.tsファイルがコンパイルされた結果、/src/appフォルダー配下には、
- .tsファイルと同名の.jsファイル(=コンパイル済みJavaScriptファイル)
- .js.mapファイル(=マップファイル)
ができていることも確認しておきましょう。
[Note]npm startコマンド
npm startコマンドは、package.jsonファイル(リスト7)で定義されたコマンドです。
"scripts": {
……中略……
"start": "concurrently \"npm run build:watch\" \"npm run serve\"",
"pree2e": "npm run build:e2e",
……中略……
},
ここでは、以下の内容を定義しています。
- npm run build:watchコマンドで、TypeScriptスクリプトをコンパイルし、また、ファイルの変更監視を開始
- npm run serveコマンドで、サーバーを起動
concurrentlyは、指定された命令を並列に実行しなさい、という意味です。
以上、QuickStartをベースにして、Angularアプリの構造を理解すると共に、アプリを実際に起動させるまでの基本的な開発の流れを見てみました。
こうして見てみると、「簡単なアプリを動かすにも、さまざまなファイルが絡み合っているので、Angularは難しい!」と思われるかもしれません。しかし、ここまでの内容は、一般的なアプリではほぼ共通です。QuickStartをスケルトンとして、以降のコードを追加していくようにすると、開発を効率化できるでしょう。
本連載でも、以降、QuickStartのコードを前提として、そこからの差分を解説していきます。
処理対象:“Hello World” カテゴリ:基本
処理対象:ルートモジュール カテゴリ:基本
処理対象:ルートコンポーネント カテゴリ:基本
処理対象:main.ts カテゴリ:基本
API:NgModule カテゴリ:@angular > core > INTERFACE(インターフェース)|ADVANCED > Angular Modules
API:@NgModuleデコレーター カテゴリ:ADVANCED > Angular Modules
API:BrowserModule カテゴリ:@angular > platform-browser > CLASS(クラス)|ADVANCED > Angular Modules
API:@Component カテゴリ:@angular > core > Component decorator(コンポーネントデコレーター)
API:platformBrowserDynamic カテゴリ:@angular > core > platform-browser-dynamic > CONST(定数)
API:import|export カテゴリ:TypeScript/JavaScript > 文法
Copyright© Digital Advantage Corp. All Rights Reserved.