SPAの統合

angularで記述されたシングルページアプリケーション(SPA)のソースコードをAdobe Experience Manager(AEM)プロジェクトと統合する方法を説明します。 webpack開発サーバーなどの最新のフロントエンドツールを使用して、AEM JSONモデルAPIに対するSPAを迅速に開発する方法を説明します。

目的

  1. SPAプロジェクトとAEMをクライアント側ライブラリと統合する方法について説明します。
  2. 専用のフロントエンド開発にローカル開発・サーバを使用する方法を説明します。
  3. AEM JSONモデルAPIに対する開発に、proxy​と静的​mock​ファイルの使用を調べます

作成する内容

この章では、単純なHeaderコンポーネントをSPAに追加します。 この静的なHeaderコンポーネントを構築する過程で、AEM SPA開発に対していくつかのアプローチが使用されます。

AEMの新しいヘッダー

SPAが拡張され、静的コンポーネントが追加さ Header れます

前提条件

ローカル開発環境の設定に必要なツールと手順を確認します。

コードの取得

  1. このチュートリアルの開始点をGitからダウンロードします。

    $ git clone git@github.com:adobe/aem-guides-wknd-spa.git
    $ cd aem-guides-wknd-spa
    $ git checkout Angular/integrate-spa-start
    
  2. Mavenを使用して、コードベースをローカルのAEMインスタンスにデプロイします。

    $ mvn clean install -PautoInstallSinglePackage
    

    AEM 6.xを使用する場合は、classicプロファイルを追加します。

    $ mvn clean install -PautoInstallSinglePackage -Pclassic
    

GitHubで完成したコードをいつでも表示したり、ブランチAngular/integrate-spa-solutionに切り替えてコードをローカルでチェックアウトしたりできます。

統合アプローチ

AEMプロジェクトの一部として、2つのモジュールが作成されました。ui.appsui.frontendが表示されます。

ui.frontendモジュールは、すべてのSPAソースコードを含むwebpackプロジェクトです。 SPAの開発およびテストの大部分は、webpackプロジェクトでおこなわれます。 実稼動ビルドがトリガーされると、SPAはwebpackを使用して構築およびコンパイルされます。 コンパイル済みのアーティファクト(CSSおよびJavaScript)がui.appsモジュールにコピーされ、AEMランタイムにデプロイされます。

ui.frontendハイレベルアーキテクチャ

SPA統合の概要です。

フロントエンドビルドに関する追加情報は、こちらを参照してください。

InspectとSPAの統合

次に、 ui.frontendモジュールを調べて、AEMプロジェクトのアーキタイプによって自動生成されたSPAを理解します。

  1. 任意のIDEで、WKND SPA用のAEMプロジェクトを開きます。 このチュートリアルでは、Visual Studio Code IDEを使用します。

    VSCode - AEM WKND SPA Project

  2. ui.frontendフォルダーを展開し、検査します。 ファイルui.frontend/package.jsonを開きます。

  3. dependenciesの下に、@angularに関連する次の要素が表示されます。

    "@angular/animations": "~9.1.11",
    "@angular/common": "~9.1.11",
    "@angular/compiler": "~9.1.11",
    "@angular/core": "~9.1.11",
    "@angular/forms": "~9.1.10",
    "@angular/platform-browser": "~9.1.10",
    "@angular/platform-browser-dynamic": "~9.1.10",
    "@angular/router": "~9.1.10",
    

    ui.frontendモジュールは、ルーティングを含むAngularCLIツールを使用して生成されたAngularアプリケーションです。

  4. また、@adobeというプレフィックスが付いた依存関係は3つあります。

    "@adobe/cq-angular-editable-components": "^2.0.2",
    "@adobe/cq-spa-component-mapping": "^1.0.3",
    "@adobe/cq-spa-page-model-manager": "^1.1.3",
    

    上記のモジュールは、AEM SPA Editor JS SDKを構成し、SPAコンポーネントをAEMコンポーネントにマッピングできるようにする機能を提供します。

  5. package.jsonファイルでは、複数のscriptsが定義されます。

    "scripts": {
        "start": "ng serve --open --proxy-config ./proxy.conf.json",
        "build": "ng lint && ng build && clientlib",
        "build:production": "ng lint && ng build --prod && clientlib",
        "test": "ng test",
        "sync": "aemsync -d -w ../ui.apps/src/main/content"
    }
    

    これらのスクリプトは、一般的なAngularCLIコマンドに基づいていますが、大きなAEMプロジェクトで動作するように若干変更されています。

    start :ローカルWebAngularを使用して、サーバーアプリをローカルで実行します。ローカルのAEMインスタンスのコンテンツをプロキシするように更新されました。

    build :実稼動用にAngularアプリをコンパイルします。ビルド中に、コンパイル済みのSPAをクライアント側ライブラリとしてui.appsモジュールにコピーする役割を&& clientlibを追加しました。 npmモジュールaem-clientlib-generatorを使用して、これを容易にします。

    使用可能なスクリプトの詳細は、こちらを参照してください。

  6. ui.frontend/clientlib.config.js ファイルを検査します。この設定ファイルは、aem-clientlib-generatorでクライアントライブラリの生成方法を決定するために使用されます。

  7. ui.frontend/pom.xml ファイルを検査します。このファイルは、ui.frontendフォルダーをMavenモジュールに変換します。 pom.xmlファイルが更新され、Mavenのビルド中にfrontend-maven-pluginを​test​および​build​にSPAを使用するようになりました。

  8. ui.frontend/src/app/app.component.tsにあるファイルapp.component.tsをInspectにします。

    import { Constants } from '@adobe/cq-angular-editable-components';
    import { ModelManager } from '@adobe/cq-spa-page-model-manager';
    import { Component } from '@angular/core';
    
    @Component({
    selector: '#spa-root', // tslint:disable-line
    styleUrls: ['./app.component.css'],
    templateUrl: './app.component.html'
    })
    export class AppComponent {
        ...
    
        constructor() {
            ModelManager.initialize().then(this.updateData);
        }
    
        private updateData = pageModel => {
            this.path = pageModel[Constants.PATH_PROP];
            this.items = pageModel[Constants.ITEMS_PROP];
            this.itemsOrder = pageModel[Constants.ITEMS_ORDER_PROP];
        }
    }
    

    app.component.js は、SPAのエントリポイントです。ModelManager は、AEM SPA Editor JS SDKで提供されます。これは、を呼び出し、アプリケーションにpageModel (JSONコンテンツ)を挿入する役割を果たします。

ヘッダーコンポーネントの追加

次に、SPAに新しいコンポーネントを追加し、変更をローカルのAEMインスタンスにデプロイして統合を確認します。

  1. 新しいターミナルウィンドウを開き、ui.frontend フォルダーに移動します。

    $ cd aem-guides-wknd-spa/ui.frontend
    
  2. AngularCLIをグローバルにインストールします。これは、Angularコンポーネントを生成し、ng​コマンドを使用してAngularアプリケーションを構築して提供するために使用されます。

    $ npm install -g @angular/cli
    
    注意

    このプロジェクトで使用される​**@angular/cli**​のバージョンは​9.1.7​です。 angularCLIのバージョンを同期させることをお勧めします。

  3. ui.frontendフォルダー内からAngularCLI ng generate componentコマンドを実行して、新しいHeaderコンポーネントを作成します。

    $ ng generate component components/header
    
    CREATE src/app/components/header/header.component.css (0 bytes)
    CREATE src/app/components/header/header.component.html (21 bytes)
    CREATE src/app/components/header/header.component.spec.ts (628 bytes)
    CREATE src/app/components/header/header.component.ts (269 bytes)
    UPDATE src/app/app.module.ts (1809 bytes)
    

    これにより、ui.frontend/src/app/components/headerに新しいAngularヘッダーコンポーネントのスケルトンが作成されます。

  4. 任意のIDEでaem-guides-wknd-spaプロジェクトを開きます。 ui.frontend/src/app/components/header フォルダーに移動し、

    IDEでのヘッダーコンポーネントのパス

  5. ファイルheader.component.htmlを開き、内容を次のように置き換えます。

    <!--/* header.component.html */-->
    <header className="header">
        <div className="header-container">
            <h1>WKND</h1>
        </div>
    </header>
    

    これにより静的コンテンツが表示されるので、このAngularコンポーネントでは、デフォルトで生成されたheader.component.tsを調整する必要はありません。

  6. ui.frontend/src/app/app.component.htmlにある​app.component.html​ファイルを開きます。 app-headerを追加します。

    <app-header></app-header>
    <router-outlet></router-outlet>
    

    これにより、すべてのページコンテンツの上にheaderコンポーネントが含まれます。

  7. 新しいターミナルを開き、ui.frontendフォルダーに移動してnpm run buildコマンドを実行します。

    $ cd ui.frontend
    $ npm run build
    
    Linting "angular-app"...
    All files pass linting.
    Generating ES5 bundles for differential loading...
    ES5 bundle generation complete.
    
  8. ui.apps フォルダーに移動し、ui.apps/src/main/content/jcr_root/apps/wknd-spa-angular/clientlibs/clientlib-angularの下に、コンパイル済みのSPAファイルがui.frontend/buildフォルダーからコピーされているのがわかります。

    ui.appsで生成されたクライアントライブラリ

  9. ターミナルに戻り、 ui.appsフォルダーに移動します。 次のMavenコマンドを実行します。

    $ cd ../ui.apps
    $ mvn clean install -PautoInstallPackage
    ...
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time:  9.629 s
    [INFO] Finished at: 2020-05-04T17:48:07-07:00
    [INFO] ------------------------------------------------------------------------
    

    これにより、AEMのローカル実行インスタンスにui.appsパッケージがデプロイされます。

  10. ブラウザータブを開き、http://localhost:4502/editor.html/content/wknd-spa-angular/us/en/home.htmlに移動します。 これで、Headerコンポーネントの内容がSPAに表示されます。

初期ヘッダー実装

手順​7~9​は、プロジェクトのルートからMavenビルドをトリガーすると(mvn clean install -PautoInstallSinglePackage)自動的に実行されます。 これで、SPAとAEMのクライアント側ライブラリ間の統合の基本を理解する必要があります。 AEMでは引き続きTextコンポーネントを編集および追加できますが、Headerコンポーネントは編集できません。

Webpack Dev Server - JSON APIのプロキシ

前の演習で見たように、クライアントライブラリをビルドしてAEMのローカルインスタンスに同期するには、数分かかります。 これは最終テストでは許容されますが、SPA開発の大部分には理想的ではありません。

webpack開発サーバーを使用して、SPAを迅速に開発できます。 SPAは、AEMで生成されたJSONモデルによって駆動されます。 この演習では、AEMの実行中のインスタンスのJSONコンテンツを、Angularプロジェクト🔗によって設定された開発サーバーに​プロキシします。

  1. IDEに戻り、ui.frontend/proxy.conf.jsonにある​proxy.conf.json​ファイルを開きます。

    [
        {
            "context": [
                        "/content/**/*.(jpg|jpeg|png|model.json)",
                        "/etc.clientlibs/**/*"
                    ],
            "target": "http://localhost:4502",
            "auth": "admin:admin",
            "logLevel": "debug"
        }
    ]
    

    Angularアプリは、APIリクエストを簡単にプロキシするメカニズムを提供します。 contextで指定されたパターンは、ローカルのAEM quickstartであるlocalhost:4502を介してプロキシ化されます。

  2. ui.frontend/src/index.htmlにある​index.html​ファイルを開きます。 これは、開発サーバーで使用されるルートHTMLファイルです。

    base href="/"のエントリがあることに注意してください。 baseタグは、アプリが相対URLを解決するのに重要です。

    <base href="/">
    
  3. ターミナルウィンドウを開き、 ui.frontendフォルダーに移動します。 npm start コマンドを実行します。

    $ cd ui.frontend
    $ npm start
    
    > wknd-spa-angular@0.1.0 start /Users/dgordon/Documents/code/aem-guides-wknd-spa/ui.frontend
    > ng serve --open --proxy-config ./proxy.conf.json
    
    10% building 3/3 modules 0 active[HPM] Proxy created: [ '/content/**/*.(jpg|jpeg|png|model.json)', '/etc.clientlibs/**/*' ]  ->  http://localhost:4502
    [HPM] Subscribed to http-proxy events:  [ 'error', 'close' ]
    ℹ 「wds」: Project is running at http://localhost:4200/webpack-dev-server/
    ℹ 「wds」: webpack output is served from /
    ℹ 「wds」: 404s will fallback to //index.html
    
  4. 新しいブラウザータブを開き(まだ開いていない場合)、http://localhost:4200/content/wknd-spa-angular/us/en/home.htmlに移動します。

    Webpack開発サーバー — プロキシjson

    AEMと同じコンテンツが表示されますが、オーサリング機能が有効になっていないはずです。

  5. IDEに戻り、imgという名前の新しいフォルダーをui.frontend/src/assetsに作成します。

  6. 次のWKNDロゴをダウンロードし、imgフォルダーに追加します。

    WKNDロゴ

  7. header.component.html​をui.frontend/src/app/components/header/header.component.htmlで開き、次のロゴを含めます。

    <header class="header">
        <div class="header-container">
            <div class="logo">
                <img class="logo-img" src="assets/img/wknd-logo-dk.png" alt="WKND SPA" />
            </div>
        </div>
    </header>
    

    変更を​header.component.html​に保存します。

  8. ブラウザーに戻ります。 アプリに対する変更がすぐに反映されていることを確認します。

    ヘッダーに追加されたロゴ

    コンテンツをプロキシしているので、AEM​でコンテンツを更新し続け、webpack開発サーバー​に反映されていることを確認できます。 コンテンツの変更は、webpack開発サーバー​にのみ表示されます。

  9. ターミナルでctrl+cを使用してローカルWebサーバーを停止します。

Webpack Dev Server — モックJSON API

迅速な開発のもう1つのアプローチは、静的JSONファイルをJSONモデルとして機能させることです。 JSONを「モック」することで、ローカルのAEMインスタンスへの依存関係を削除します。 また、フロントエンド開発者は、機能をテストし、JSON APIに対する変更を促進するためにJSONモデルを更新でき、後でバックエンド開発者によって実装されます。

モックJSONの初期設定には、ローカルのAEMインスタンス​が必要です。

  1. ブラウザーで、http://localhost:4502/content/wknd-spa-angular/us/en.model.jsonに移動します。

    これは、アプリケーションを実行している AEM から書き出した JSON です。JSON 出力をコピーします。

  2. IDEに戻り、ui.frontend/srcに移動し、mocks​および​json​という名前の新しいフォルダーを追加して、次のフォルダー構造に一致させます。

    |-- ui.frontend
        |-- src
            |-- mocks
                |-- json
    
  3. ui.frontend/public/mocks/jsonの下に​en.model.json​という名前の新しいファイルを作成します。 手順1​のJSON出力をここに貼り付けます。

    モックモデルJsonファイル

  4. ui.frontendの下に、新しいファイル​proxy.mock.conf.json​を作成します。 ファイルに以下のように入力します。

    [
        {
        "context": [
            "/content/**/*.model.json"
        ],
        "pathRewrite": { "^/content/wknd-spa-angular/us" : "/mocks/json"} ,
        "target": "http://localhost:4200",
        "logLevel": "debug"
        }
    ]
    

    このプロキシ設定は、/content/wknd-spa-angular/usで始まる要求を/mocks/jsonで書き換え、対応する静的JSONファイルを提供します。次に例を示します。

    /content/wknd-spa-angular/us/en.model.json -> /mocks/json/en.model.json
    
  5. ファイル​angular.json​を開きます。 新しい​dev​設定を追加し、更新された​assets​配列を使用して、作成された​mocks​フォルダーを参照します。

     "dev": {
              "assets": [
                "src/mocks",
                "src/assets",
                "src/favicon.ico",
                "src/logo192.png",
                "src/logo512.png",
                "src/manifest.json"
              ]
        },
    

    AngularのJSON開発用アセットの更新フォルダー

    専用の​dev​設定を作成すると、mocks​フォルダーは開発時にのみ使用され、実稼動ビルドではAEMにデプロイされなくなります。

  6. angular.json​ファイルで、次に​browserTarget​設定を更新し、新しい​dev​設定を使用します。

      ...
      "serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
    +       "browserTarget": "angular-app:build:dev"
    -       "browserTarget": "angular-app:build"
          },
      ...
    

    AngularJSONビルド開発の更新

  7. ファイルui.frontend/package.jsonを開き、新しい​start:mock​コマンドを追加して、proxy.mock.conf.json​ファイルを参照します。

        "scripts": {
            "start": "ng serve --open --proxy-config ./proxy.conf.json",
    +       "start:mock": "ng serve --open --proxy-config ./proxy.mock.conf.json",
            "build": "ng lint && ng build && clientlib",
            "build:production": "ng lint && ng build --prod && clientlib",
            "test": "ng test",
            "sync": "aemsync -d -w ../ui.apps/src/main/content"
        }
    

    新しいコマンドを追加すると、プロキシ設定を簡単に切り替えることができます。

  8. 現在実行中の場合は、webpack開発サーバー​を停止します。 start:mock​スクリプトを使用して、webpack開発サーバー​を起動します。

    $ npm run start:mock
    
    > wknd-spa-angular@0.1.0 start:mock /Users/dgordon/Documents/code/aem-guides-wknd-spa/ui.frontend
    > ng serve --open --proxy-config ./proxy.mock.conf.json
    

    http://localhost:4200/content/wknd-spa-angular/us/en/home.htmlに移動すると、同じSPAが表示されますが、コンテンツは​mock JSONファイルから取り込まれます。

  9. 先ほど作成した​en.model.json​ファイルに小さな変更を加えます。 更新されたコンテンツは、webpack開発サーバー​に直ちに反映されます。

    モックモデルのjsonの更新

    JSONモデルを操作し、実際のSPAへの影響を確認できることは、開発者がJSONモデルAPIを理解するのに役立ちます。 また、フロントエンドとバックエンドの両方の開発を並行しておこなうこともできます。

Sassでスタイルを追加

次に、更新されたスタイルがプロジェクトに追加されます。 このプロジェクトでは、変数などの便利な機能にSassのサポートを追加します。

  1. ターミナルウィンドウを開き、起動した場合は​webpack開発サーバー​を停止します。 ui.frontendフォルダー内から次のコマンドを入力し、Angularアプリを更新して​.scss​ファイルを処理します。

    $ cd ui.frontend
    $ ng config schematics.@schematics/angular:component.styleext scss
    

    これにより、angular.jsonファイルが更新され、ファイルの下部に新しいエントリが表示されます。

    "schematics": {
        "@schematics/angular:component": {
        "styleext": "scss"
        }
    }
    
  2. ブラウザー間でスタイルを正規化するには、normalize-scssをインストールします。

    $ npm install normalize-scss --save
    
  3. IDEに戻り、ui.frontend/srcの下にstylesという名前の新しいフォルダーを作成します。

  4. ui.frontend/src/stylesの下に_variables.scssという名前の新しいファイルを作成し、次の変数を設定します。

    //_variables.scss
    
    //== Colors
    //
    //## Gray and brand colors for use across theme.
    
    $black:                  #202020;
    $gray:                   #696969;
    $gray-light:             #EBEBEB;
    $gray-lighter:           #F7F7F7;
    $white:                  #FFFFFF;
    $yellow:                 #FFEA00;
    $blue:                   #0045FF;
    
    
    //== Typography
    //
    //## Font, line-height, and color for body text, headings, and more.
    
    $font-family-sans-serif:  "Helvetica Neue", Helvetica, Arial, sans-serif;
    $font-family-serif:       Georgia, "Times New Roman", Times, serif;
    $font-family-base:        $font-family-sans-serif;
    $font-size-base:          18px;
    
    $line-height-base:        1.5;
    $line-height-computed:    floor(($font-size-base * $line-height-base));
    
    // Functional Colors
    $brand-primary:             $yellow;
    $body-bg:                   $white;
    $text-color:                $black;
    $text-color-inverse:        $gray-light;
    $link-color:                $blue;
    
    //Layout
    $max-width: 1024px;
    $header-height: 75px;
    
    // Spacing
    $gutter-padding: 12px;
    
  5. ファイル​styles.css​の拡張子の名前をui.frontend/src/styles.cssから​styles.scss​に変更します。 内容を次のように置き換えます。

    /* styles.scss * /
    
    /* Normalize */
    @import '~normalize-scss/sass/normalize';
    
    @import './styles/variables';
    
    body {
        background-color: $body-bg;
        font-family: $font-family-base;
        margin: 0;
        padding: 0;
        font-size: $font-size-base;
        text-align: left;
        color: $text-color;
        line-height: $line-height-base;
    }
    
    body.page {
        max-width: $max-width;
        margin: 0 auto;
        padding: $gutter-padding;
        padding-top: $header-height;
    }
    
  6. angular.json​を更新し、style.css​へのすべての参照を​styles.scss​で名前変更します。 3つの参照が必要です。

      "styles": [
    -    "src/styles.css"
    +    "src/styles.scss"
       ],
    

ヘッダースタイルの更新

次に、Sassを使用して、Header​コンポーネントにブランド固有のスタイルを追加します。

  1. webpack開発サーバー​を起動して、スタイルの更新をリアルタイムで確認します。

    $ npm run start:mock
    
  2. ui.frontend/src/app/components/headerの下で、header.component.css​を​header.component.scss​に名前変更します。 ファイルに以下のように入力します。

    @import "~src/styles/variables";
    
    .header {
        width: 100%;
        position: fixed;
        top: 0;
        left:0;
        z-index: 99;
        background-color: $brand-primary;
        box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.24);
    }
    
    .header-container {
        display: flex;
        max-width: $max-width;
        margin: 0 auto;
        padding-left: $gutter-padding;
        padding-right: $gutter-padding;
    }
    
    .logo {
        z-index: 100;
        display: flex;
        padding-top: $gutter-padding;
        padding-bottom: $gutter-padding;
    }
    
    .logo-img {
        width: 100px;
    }
    
  3. header.component.js​を更新して、header.component.scss​を参照します。

    ...
      @Component({
        selector: 'app-header',
        templateUrl: './header.component.html',
    -   styleUrls: ['./header.component.css']
    +   styleUrls: ['./header.component.scss']
      })
    ...
    
  4. ブラウザーに戻り、webpack開発サーバー​に戻ります。

    スタイル設定ヘッダー — webpack devサーバー

    更新されたスタイルが​Header​コンポーネントに追加されているのがわかります。

AEMへのSPAアップデートのデプロイ

ヘッダー​に加えられた変更は、現在、webpack開発サーバー​でのみ表示されます。 更新したSPAをAEMにデプロイして、変更を確認します。

  1. webpack開発サーバー​を停止します。

  2. プロジェクト/aem-guides-wknd-spaのルートに移動し、Mavenを使用してAEMにプロジェクトをデプロイします。

    $ cd ..
    $ mvn clean install -PautoInstallSinglePackage
    
  3. http://localhost:4502/editor.html/content/wknd-spa-angular/us/en/home.htmlに移動します。 ロゴとスタイルが適用された更新済みの​Header​が表示されます。

    AEMのヘッダーの更新

    更新されたSPAがAEMになったので、オーサリングを続行できます。

おめでとうございます。

これで、SPAを更新し、AEMとの統合を確認しました。 webpack開発サーバー​を使用してAEM JSONモデルAPIに対するSPAを開発する方法が2つあります。

GitHubで完成したコードをいつでも表示したり、ブランチAngular/integrate-spa-solutionに切り替えてコードをローカルでチェックアウトしたりできます。

次の手順

SPAコンポーネントのAEMコンポーネントへのマッピング - AEM SPA Editor JS SDKを使用して、AngularコンポーネントをAdobe Experience Manager(AEM)コンポーネントにマッピングする方法を説明します。コンポーネントマッピングを使用すると、作成者は、AEM SPAエディター内で、従来のAEMオーサリングと同様に、SPAコンポーネントを動的に更新できます。

このページ