Angular を使用した AEM での SPA の概要 getting-started-with-spas-in-aem-using-angular
単一ページアプリケーション(SPA)により、Web サイトのユーザーに魅力的なエクスペリエンスを提供することができます。開発者にとっては、SPA フレームワークを使用してサイトを構築できると都合がよく、作成者にとっては、SPA フレームワークを使用して構築されたサイトのコンテンツを AEM 内でシームレスに編集できると便利です。
SPA オーサリング機能には、AEM 内で SPA をサポートするための包括的なソリューションが用意されています。この記事では、Angular フレームワーク上のシンプルな SPA アプリケーションを紹介し、その組み合わせ方法を説明します。これにより、独自の SPA をすぐに使い始めることができます。
はじめに introduction
この記事では、シンプルな SPA の基本的な機能と、SPA を運用するための最低条件の概要を説明します。
AEM での SPA の動作について詳しくは、次のドキュメントを参照してください。
このドキュメントでは、簡略化された SPA の構造と仕組みを説明します。お客様の SPA にも応用できる内容になっています。
依存関係、設定、ビルド dependencies-configuration-and-building
サンプルの SPA では、必要な Angular の依存関係以外に、追加のライブラリも使用して SPA の作成を効率化できます。
依存関係 dependencies
package.json
ファイルは、SPA パッケージ全体の要件を定義します。必要最小限の AEM 依存関係を以下に示します。
"dependencies": {
"@adobe/aem-angular-editable-components": "~1.0.3",
"@adobe/aem-spa-component-mapping": "~1.0.5",
"@adobe/aem-spa-page-model-manager": "~1.0.3"
}
aem-clientlib-generator
は、クライアントライブラリの作成をビルドプロセスの一部として自動化しています。
"aem-clientlib-generator": "^1.4.1",
詳しくは、GitHub の aem-clientlib-generator を参照してください。
aem-clientlib-generator
は、clientlib.config.js
ファイルで次のように設定されています。
module.exports = {
// default working directory (can be changed per 'cwd' in every asset option)
context: __dirname,
// path to the clientlib root folder (output)
clientLibRoot: "./../content/jcr_root/apps/my-angular-app/clientlibs",
libs: {
name: "my-angular-app",
allowProxy: true,
categories: ["my-angular-app"],
embed: ["my-angular-app.responsivegrid"],
jsProcessor: ["min:gcc"],
serializationFormat: "xml",
assets: {
js: [
"dist/**/*.js"
],
css: [
"dist/**/*.css"
]
}
}
};
ビルド building
アプリの実際のビルドでは、クライアントライブラリの自動作成用の aem-clientlib-generator 以外に、トランスパイル用に Webpack も使用します。したがって、build コマンドは次のようになります。
"build": "ng build --build-optimizer=false && clientlib",
ビルドが完了したら、パッケージを AEM インスタンスにアップロードできます。
AEM プロジェクトアーキタイプ aem-project-archetype
AEM プロジェクトでは、 AEM プロジェクトアーキタイプを使用します。このアーキタイプは、React または Angular を使用する SPA プロジェクトをサポートし、SPA SDK を使用します。
アプリケーション構造 application-structure
以前に説明したように依存関係を追加してアプリをビルドすると、AEM インスタンスにアップロードできる SPA パッケージが作成されます。
このドキュメントの次の節では、AEM での SPA の構造と、アプリケーションの動作にかかわる重要なファイルのほか、それらのファイルがどのように連携するのかについて説明します。
シンプルな画像コンポーネントを例として使用していますが、このアプリケーションのコンポーネントはすべて同じ概念に基づいています。
app.module.ts app-module-ts
SPA のエントリポイントは app.module.ts
ファイルです。このファイルの内容を以下に示しますが、重要な部分のみに焦点を当てるために簡略化されています。
// app.module.ts
import { BrowserModule, BrowserTransferStateModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { SpaAngularEditableComponentsModule } from '@adobe/aem-angular-editable-components';
import { AppRoutingModule } from './app-routing.module';
@NgModule({
imports: [ BrowserModule.withServerTransition({ appId: 'my-angular-app' }),
SpaAngularEditableComponentsModule,
AppRoutingModule,
BrowserTransferStateModule ],
providers: ...,
declarations: [ ... ],
entryComponents: [ ... ],
bootstrap: [ AppComponent ]
})
export class AppModule {}
app.module.ts
ファイルはアプリの開始点で、初期プロジェクト設定が含まれ、AppComponent
を使用してアプリをブートストラップします。
静的インスタンス化 static-instantiation
コンポーネントテンプレートを使用して静的にコンポーネントをインスタンス化する場合、値はモデルからコンポーネントのプロパティに渡す必要があります。モデルの値は属性として渡され、後でコンポーネントプロパティとして使用できます。
app.component.ts app-component-ts
app.module.ts
が AppComponent
をブートストラップすると、アプリを初期化することができます。ここでは、重要なコンテンツに焦点を当てるための簡略化されたバージョンを示します。
// app.component.ts
import { Component } from '@angular/core';
import { ModelManager } from '@adobe/aem-spa-page-model-manager';
import { Constants } from "@adobe/aem-angular-editable-components";
@Component({
selector: 'app-root',
template: `
<router-outlet></router-outlet>
`
})
export class AppComponent {
items;
itemsOrder;
path;
constructor() {
ModelManager.initialize().then(this.updateData.bind(this));
}
private updateData(model) {
this.path = model[Constants.PATH_PROP];
this.items = model[Constants.ITEMS_PROP];
this.itemsOrder = model[Constants.ITEMS_ORDER_PROP];
}
}
main-content.component.ts main-content-component-ts
ページを処理することで、app.component.ts
が main-content.component.ts
を呼び出します(ここでは簡略化されて示されています)。
import { Component } from '@angular/core';
import { ModelManagerService } from '../model-manager.service';
import { ActivatedRoute } from '@angular/router';
import { Constants } from "@adobe/aem-angular-editable-components";
@Component({
selector: 'app-main',
template: `
<aem-page class="structure-page" [attr.data-cq-page-path]="path" [cqPath]="path" [cqItems]="items" [cqItemsOrder]="itemsOrder" ></aem-page>
`
})
export class MainContentComponent {
items;
itemsOrder;
path;
constructor( private route: ActivatedRoute,
private modelManagerService: ModelManagerService) {
this.modelManagerService.getData({ path: this.route.snapshot.data.path }).then((data) => {
this.path = data[Constants.PATH_PROP];
this.items = data[Constants.ITEMS_PROP];
this.itemsOrder = data[Constants.ITEMS_ORDER_PROP];
});
}
}
MainComponent
は、ページモデルの JSON 表現を取り込み、コンテンツを処理してページの各要素をラップ/デコレートします。Page
のその他の詳細については、SPA ブループリントのドキュメントを参照してください。
image.component.ts image-component-ts
Page
は、コンポーネントで構成されています。JSON を取得すると、Page
は次に示すように image.component.ts
のようなコンポーネントを処理できます。
/// image.component.ts
import { Component, Input } from '@angular/core';
const ImageEditConfig = {
emptyLabel: 'Image',
isEmpty: function(cqModel) {
return !cqModel || !cqModel.src || cqModel.src.trim().length < 1;
}
};
@Component({
selector: 'app-image',
templateUrl: './image.component.html',
})
export class ImageComponent {
@Input() src: string;
@Input() alt: string;
@Input() title: string;
}
MapTo('my-angular-app/components/image')(ImageComponent, ImageEditConfig);
AEM の SPA の中核概念は、SPA コンポーネントを AEM コンポーネントにマッピングし、コンテンツが変更されたときにコンポーネントも更新する(またはその逆も含む)というものです。この通信モデルの概要については、SPA エディターの概要のドキュメントを参照してください。
MapTo('my-angular-app/components/image')(Image, ImageEditConfig);
MapTo
メソッドは、SPA コンポーネントを AEM コンポーネントにマッピングします。単一の文字列または文字列の配列の使用に対応しています。
ImageEditConfig
は、エディターがプレースホルダーを生成するために必要なメタデータを提供することで、コンポーネントのオーサリング機能の有効化に関与する設定オブジェクトです。
コンテンツがない場合は、空のコンテンツを表すラベルがプレースホルダーとして提供されます。
動的に渡されるプロパティ dynamically-passed-properties
モデルからのデータは、コンポーネントのプロパティとして動的に渡されます。
image.component.html image-component-html
最後に、image.component.html
でイメージをレンダリングできます。
// image.component.html
<img [src]="src" [alt]="alt" [title]="title"/>
SPA コンポーネント間での情報の共有 sharing-information-between-spa-components
単一ページのアプリケーション内のコンポーネントが情報を共有することは定期的に必要です。これを行う推奨方法にはいくつかあり、以下に簡単なものから順に示します。
- オプション 1: 例えば、util クラスを純粋なオブジェクト指向のソリューションとして使用して、ロジックを一元化し、必要なコンポーネントにブロードキャストします。
- オプション 2:NgRx などのステートライブラリを使用して、コンポーネントの状態を共有します。
- オプション 3:コンテナコンポーネントをカスタマイズおよび拡張することで、オブジェクト階層を活用します。
次の手順 next-steps
- React を使用した AEM での SPA の概要では、SPA エディターで動作する基本的な SPA の構築方法を示しています。
- 「SPA エディターの概要」では、AEM と SPA 間の通信モデルをより深く分析しています。
- WKND SPA プロジェクトは、AEM で簡単な SPA プロジェクトを実装するための、手順を追ったチュートリアルです。
- SPA の動的モデルからコンポーネントへのマッピングでは、動的モデルとコンポーネントのマッピング、および AEM の SPA 内での動作方法について説明しています。
- SPA ブループリントは、React や Angular 以外のフレームワーク用に、AEM に SPA を実装する場合や、単に理解を深めたい場合に、AEM 用の SPA SDK の詳しい仕組みを提供します。