Angular TIPS

Angular TIPS

Angularの基本構造を理解して、アプリ開発を始めるには?

2017年5月24日

初めてのAngular開発【v4以降対応】。誤解のしようもない最も基本的な“Hello World”を作成して、Angularアプリの基本構造を理解しよう。

  • このエントリーをはてなブックマークに追加

【対応バージョン】 Angular 4以降。v2初期時点のインストール方法に関しては「Angular 2を利用するには?(実装編)」を参照してください。

 別稿「TIPS:Angularの特徴とは? 開発環境を構築するには?」(以降、準備編)では、Angularとは、に始まり、Angular QuickStart Source(以降、QuickStart)を利用して、Angularアプリの骨格を準備、インストールするまでを済ませました。本稿では、準備編で作成したアプリにあらかじめ用意されているサンプルアプリ(つまりQuickStartに含まれているソースコード)を読み解き、実際に動作させるまでを見ていきます。実践でAngular開発をしていく場合には基本的にQuickStartからスタートすればよく、本稿で説明する14の作業は不要ですが、本稿では「実際にゼロから開発する場合の流れ・手順」でソースコードを読み解いていきます。

 QuickStartで用意されているのは、「Hello Angular」を表示するだけの、ごく基本的なサンプルです(図1)。誤解のしようもない基本的なサンプルなので、「またか」と思わず、Angularアプリの基本的な構造を理解してください。

図1 決められたメッセージを表示するだけのサンプル
図1 決められたメッセージを表示するだけのサンプル

1モジュールを準備する

 モジュールとは、アプリを構成するオブジェクト(=コンポーネント)を束ねるための仕組みです。Angularそれ自体も複数のモジュールから構成されており、アプリの要件に応じて必要なモジュールをインポートして利用することになります。

 もちろん、モジュールはアプリ開発者が自ら定義することもできます。原則として、Angularアプリは、1つ以上のモジュールから構成されていなければなりません。アプリを起動する際に呼び出されるモジュールのことを、ルートモジュールとも呼びます(いわゆる、アプリのエントリーポイントを内包するメインモジュールです)。

 以下に、その具体的なコードを示します(なお、このコードは/src/appフォルダーに含まれているapp.module.tsファイルです)。

src/app/app.module.ts
// 1Angularで利用するモジュールをインポート
import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

// 2AppComponentコンポーネントをインポート
import { AppComponent }  from './app.component';

// 4モジュールに関する情報を宣言
@NgModule({
  imports:      [ BrowserModule ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
// 3モジュールクラスを準備
export class AppModule { }
リスト1 ルートモジュールAppModuleを定義するためのコード

各番号の内容は本文で詳しく説明します。34は順番が逆になっているので注意すること。

 まず、import命令で、Angularアプリを動作させるのに必要となるモジュール/コンポーネントをインポートします。

[構文]import命令

import { name, …… } from module

  • name: インポートする要素
  • module: モジュール

 1@angular/~はAngularが提供する標準モジュールです。最低限、モジュールを定義するためのNgModule、ブラウザー上でアプリを動作させるためのBrowserModuleをインポートしておきましょう*1

  • *1 あくまで最小限の構成です。本格的なアプリでは、フォームを扱うためのFormsModule、ルーティング機能を提供するRouterModuleなどをインポートする必要があります。

 2AppComponentは、アプリの本体を表すコンポーネントです。後からあらためて説明します。

 そして、3AppModuleという名前のルートモジュール(=モジュールクラス)を準備しています。他のモジュールから呼び出す際などには、ここで宣言した名前(AppModule)を利用します。

 ただし、これだけではモジュールと見なされません。@NgModuleデコレーターでモジュールとしての情報を宣言しておきましょう(4)。デコレーターは、モジュールやクラスなどの要素に対してメタ情報を付与するための仕組みです。Javaでいうところのアノテーションに相当する仕組み、と考えると、分かりやすいかもしれません。デコレーターには「パラメーター名: 値」のハッシュ形式で、あらかじめ決められたパラメーター情報を指定できます。

 @NgModuleデコレーターで利用できるパラメーターには、以下のようなものがあります。

パラメーター名 概要
imports 現在のモジュールで利用する他のモジュール/コンポーネント
exports 現在のモジュールで外部に公開するコンポーネントなど
declarations モジュール配下のコンポーネント
bootstrap 最初に起動すべき最上位のコンポーネント(=ルートコンポーネント)
表1 @NgModuleデコレーターの主なパラメーター

 この例であれば、「BrowserModuleを参照して」「ルートコンポーネントとしてAppComponentを含んだ」AppModuleモジュールを定義する、という意味になります。

2コンポーネントを準備する

 手順1で保留にしていたルートコンポーネントを作成します(リスト2)。ルートコンポーネント(もしくはメインコンポーネント)とは、アプリで最初に呼び出される、いわゆるエントリーポイントです。

src/app/app.component.ts
// 1コンポーネントで利用しているモジュールをインポート
import { Component } from '@angular/core';

// 3コンポーネントに関する情報を宣言
@Component({
  selector: 'my-app',
  template: `<h1>Hello {{name}}</h1>`,
})
// 2コンポーネントクラスを準備
export class AppComponent {
  // 4ビューに表示するための値を準備
  name = 'Angular';
}
リスト2 ルートコンポーネントAppComponentを定義するためのコード

各番号の内容は本文で説明します。32は順番が逆になっているので注意すること。

 まず、1はコンポーネントを定義するために必要となるオブジェクトをインポートしています。

 コンポーネントの本体は、2です。ここでは、先ほどAppModuleモジュールで指定したAppComponentという名前でコンポーネントクラスを作成しています。モジュールから参照できるよう、exportキーワードで外部に公開していることに注意してください。

 ただし、このままではコンポーネントとして動作させることはできません。モジュールのときと同じく、コンポーネントの構成情報を@Componentデコレーターで定義しておきましょう(3)。@Componentデコレーターでは、さまざまなパラメーターを指定できますが、ここで利用しているのは、以下の2個です*2

パラメーター名 概要
selector コンポーネントの適用先を表すセレクター式
template コンポーネントに適用するビュー(テンプレート)
表2 @Componentデコレーターの主なパラメーター
  • *2 その他のパラメーターについては、後日別稿で解説の予定です。

 この例であれば、「<my-app>要素に対して、『「<h1>Hello {{name}}</h1>」』というテンプレートを適用」するためのAppComponentコンポーネントを定義したことになります。

 テンプレートの中の{{……}}Interpolation補間)と呼ばれる構文で、主に、コンポーネントクラスで用意されたプロパティ(ここではname4)などを反映させるために利用します。Interpolationの詳細は、別稿「TIPS:コンポーネントの値をビューに反映させるには?」も併せて参照してください。

[Note]AngularモジュールとJavaScriptモジュール

 Angularで「モジュール」といった場合、2種類の意味がある点に注意してください。一つが、@NgModuleデコレーターによって宣言されたAngularモジュール、そして、もう一つがJavaScript(TypeScript)のモジュールです。

 まず、Angularモジュールは、Angularアプリを構成するコンポーネントをはじめ、サービス、ディレクティブなどを束ねる論理的な器です(アプリを特定の機能でまとめるための仕組み、と言ってもよいでしょう)。@NgModuleデコレーターによって宣言し、そのimportsパラメーターによって別のモジュールをインポートします(リスト1の4)。

 そして、JavaScript(TypeScript)のモジュールは、物理的な1つ1つのファイルです。モジュール配下のクラス/関数はexportキーワードによって外部に公開し、import命令によってインポートします(リスト3)。

TypeScript
export class AppComponent { ... }
TypeScript
import { AppComponent }  from './app.component';
リスト3 JavaScriptモジュールの外部公開(上)とインポート(下)

 Angularモジュール/JavaScriptモジュール共に、ひとくくりに「モジュール」と呼ばれるため、混同しやすいのですが、両者は別ものです。注意してください。

3スタートアップコードを準備する

 ルートモジュールとルートコンポーネントを準備できたところで、これらを起動するためのスタートアップコードを準備します。

src/main.ts
// 1アプリ起動に必要なモジュールをインポート
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

// 2モジュールを起動
platformBrowserDynamic().bootstrapModule(AppModule);
リスト4 アプリを起動するためのコード

 まず、アプリ起動のために必要なモジュールをインポートします(1)。platformBrowserDynamicはブラウザーでアプリを起動するための関数、AppModuleは自分で作成したルートモジュールです(ルートコンポーネントはAppModule経由でインポートされますので、ここではインポート不要です)。

 必要なモジュールをインポートできたら、あとは、platformBrowserDynamic#bootstrapModuleメソッドでモジュールを起動します(2)。

4メインページを準備する

 最後に、アプリを動作させるためのメインページを用意します。メインページは、(/src/appフォルダーではなく)アプリケーションルート直下(つまり/srcフォルダー)に配置するものとします。

src/index.html
<!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">

<!--1Angularの動作に必要なライブラリをインポート -->
<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>

<!--2SystemJSを起動 -->
<script src="systemjs.config.js"></script>
<script>
  System.import('main.js').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<!--3ルートコンポーネントを呼び出し-->
<my-app>Loading AppComponent content here ...</my-app>
</body>
</html>
リスト5 Angularアプリを動作するためのメインページ

 まず、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パラメーター)に合致した要素(ここでは<my-app>要素)に対して、テンプレート(templateパラメーター)の内容が反映されます。

 <my-app>要素配下には、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
...後略...
リスト6 アプリを起動するためのコマンドと実行結果の例

 これによって、TypeScriptスクリプト(.tsファイル)がコンパイルされると共に、Angular標準の開発用サーバーlite-server)が起動して、以下のようにアプリが表示されます。この状態で、ソースコード(例えばindex.htmlファイル)を書き換えると、自動的にこれを認識して、ページがリロードされることも確認してみましょう。

図2 Angularアプリを実行した結果
図2 Angularアプリを実行した結果

 .tsファイルがコンパイルされた結果、/src/appフォルダー配下には、

  • .tsファイルと同名の.jsファイル(=コンパイル済みJavaScriptファイル)
  • .js.mapファイル(=マップファイル)

ができていることも確認しておきましょう。

[Note]npm startコマンド

 npm startコマンドは、package.jsonファイル(リスト7)で定義されたコマンドです。

JSON
"scripts": {
  ……中略……
  "start": "concurrently \"npm run build:watch\" \"npm run serve\"",
  "pree2e": "npm run build:e2e",
  ……中略……
},
リスト7 package.jsonでのコマンド定義

 ここでは、以下の内容を定義しています。

  • 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 > 文法

※以下では、本稿の前後を合わせて5回分(第1回~第5回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

1. Angular 2を利用するには?(準備編)

人気のJavaScriptフレームワーク「Angular 2」の基本機能を目的別リファレンスの形式でまとめる連載スタート。まずはその特徴とインストール方法を説明する。

2. Angular 2を利用するには?(実装編)

初めてのAngular 2開発。誤解のしようもない最も基本的な“Hello World”を作成して、Angular 2アプリの基本構造を理解しよう。

3. Angularの特徴とは? 開発環境を構築するには?

人気のJavaScriptフレームワーク「Angular」の基本機能を目的別リファレンスの形式でまとめる連載の第1回【v4以降対応】。まずはその特徴とインストール方法を説明する。

4. 【現在、表示中】≫ Angularの基本構造を理解して、アプリ開発を始めるには?

初めてのAngular開発【v4以降対応】。誤解のしようもない最も基本的な“Hello World”を作成して、Angularアプリの基本構造を理解しよう。

5. コンポーネントに適用すべきテンプレートを指定するには?(template/templateUrlパラメーター)

@ComponentデコレーターのtemplateパラメーターやtemplateUrlパラメーターを使って、コンポーネントにテンプレート(ビュー)を適用する方法を説明する。

サイトからのお知らせ

Twitterでつぶやこう!