外部 SPA と AEM の間でどのレベルの統合をおこなうかを決める際に、AEM 内で SPA を表示するだけでなく、編集も必要になることがあります。
このドキュメントでは、スタンドアロン SPA を AEM インスタンスにアップロードし、編集可能なコンテンツのセクションを追加し、オーサリングを有効にするための推奨手順について説明します。
前提条件はシンプルです。
まず、外部 SPA を AEM プロジェクトにアップロードする必要があります。
/ui.frontend
プロジェクトフォルダー内の src
を、React アプリケーションの src
フォルダーに置き換えます。package.json
に追加の依存関係があれば /ui.frontend/package.json
に含めます。
/public
フォルダーにカスタマイズを含めます。/public/index.html
ファイルに含めます。これで外部 SPA が AEM プロジェクトの一部になったので、AEM 内で設定する必要があります。
AEM SPA 機能の利用は、次の 3 つのパッケージに依存しています。
@adobe/aem-react-editable-components
@adobe/aem-spa-component-mapping
@adobe/aem-spa-page-model-manager
@adobe/aem-spa-page-model-manager
は、Model Manager を初期化し、AEM インスタンスからモデルを取得する API を提供します。その後、このモデルを使用して、@adobe/aem-react-editable-components
と @adobe/aem-spa-component-mapping
の API を使用して AEM コンポーネントをレンダリングできます。
次の npm コマンドを実行して、必要なパッケージをインストールします。
npm install --save @adobe/aem-spa-component-mapping @adobe/aem-spa-page-model-manager @adobe/aem-react-editable-components
アプリケーションがレンダリングされる前に、 ModelManager
を初期化して AEM ModelStore
の作成を処理する必要があります。
これは、アプリケーションの src/index.js
ファイル内、またはアプリケーションのルートがレンダリングされる場所で行う必要があります。
このためには、ModelManager
が提供する initializationAsync
API を使用できます。
次のスクリーンショットは、単純な React アプリケーションで ModelManager
の初期化を有効にする方法を示しています。唯一の制約は、initializationAsync
を ReactDOM.render()
の前に呼び出す必要があることです。
この例では、ModelManager
が初期化され、空の ModelStore
が作成されます。
initializationAsync
は、必要に応じて、 options
オブジェクトをパラメーターとして受け入れることができます。
path
- 初期化時に、定義されたパスのモデルが取得され、ModelStore
に保存されます。これは、必要に応じて初期化時に rootModel
を取得するのに使用できます。modelClient
- モデルの取得を担当するカスタムクライアントを提供できます。model
- 通常、SSR を使用する場合に入力されるパラメーターとして渡される model
オブジェクト。認証可能な React コンポーネントが作成される AEM コンポーネントを作成または識別します。この例では、WKND プロジェクトのテキストコンポーネントを使用しています。
SPA で単純な React テキストコンポーネントを作成します。この例では、次の内容の新しいファイル Text.js
が作成されています。
AEM の編集を有効にするために必要な属性を指定する設定オブジェクトを作成します。
resourceType
は、React コンポーネントを AEM コンポーネントにマップし、AEM エディターで開いたときに編集を有効にする場合に必須です。ラッパー関数 withMappable
を使用します。
このラッパー関数は、React コンポーネントを config で指定された AEM resourceType
にマッピングし、AEM エディターで開いたときの編集機能を有効にします。スタンドアロンコンポーネントの場合は、特定のノードのモデルコンテンツも取得されます。
この例では、コンポーネントに異なるバージョン(AEM でラップされた React コンポーネントとアンラップされていないコンポーネント)があります。コンポーネントを明示的に使用する場合は、ラップされたバージョンを使用する必要があります。コンポーネントがページの一部になっている場合は、SPA エディターで現在行われているように、デフォルトのコンポーネントを引き続き使用することができます。
コンポーネント内のコンテンツをレンダリングします。
テキストコンポーネントの JCR プロパティは、AEM では次のように表示されます。
これらの値は、新しく作成された AEMText
React コンポーネントにプロパティとして渡され、コンテンツのレンダリングに使用できます。
import React from 'react';
import { withMappable } from '@adobe/aem-react-editable-components';
export const TextEditConfig = {
// Empty component placeholder label
emptyLabel:'Text',
isEmpty:function(props) {
return !props || !props.text || props.text.trim().length < 1;
},
// resourcetype of the AEM counterpart component
resourceType:'wknd-spa-react/components/text'
};
const Text = ({ text }) => (<div>{text}</div>);
export default Text;
export const AEMText = withMappable(Text, TextEditConfig);
AEM の設定が完了すると、このようにコンポーネントが表示されます。
const Text = ({ cqPath, richText, text }) => {
const richTextContent = () => (
<div className="aem_text" id={cqPath.substr(cqPath.lastIndexOf('/') + 1)} data-rte-editelement dangerouslySetInnerHTML={{__html: text}}/>
);
return richText ? richTextContent() : (<div className="aem_text">{text}</div>);
};
この例では、既存のテキストコンポーネントに合わせて、レンダリングされたコンポーネントをさらにカスタマイズしました。ただし、これは AEM でのオーサリングとは関係ありません。
認証可能な React コンポーネントが作成されたら、アプリケーション全体で使用できます。
WKND SPA プロジェクトからテキストを追加する必要があるページの例を見てみましょう。この例では、「Hello World!」というテキストを/content/wknd-spa-react/us/en/home.html
に表示します。
表示するノードのパスを指定します。
pagePath
:ノードを含むページ(この例では /content/wknd-spa-react/us/en/home
)itemPath
:ページ内のノードへのパス(この例では root/responsivegrid/text
)
コンポーネントをページ内の必要な位置に追加します。
AEMText
コンポーネントは、pagePath
値と itemPath
値をプロパティとして設定して、ページ内の必要な位置に追加できます。pagePath
は必須プロパティです。
これで、実行中の AEM インスタンスでコンポーネントをテストできます。
aem-guides-wknd-spa
ディレクトリから次の Maven コマンドを実行し、プロジェクトを構築して AEM にデプロイします。mvn clean install -PautoInstallSinglePackage
http://<host>:<port>/editor.html/content/wknd-spa-react/us/en/home.html
に移動します。AEMText
コンポーネントが、AEM 上で認証できるようになりました。
SPA でのオーサリング用に追加するページを指定します。この例では /content/wknd-spa-react/us/en/home.html
を使用しています。
新しいファイル(Page.js
)を認証可能なページコンポーネントに置き換えます。ここでは、@adobe/cq-react-editable-components
で提供されるページコンポーネントを再利用できます。
AEM 認証可能なリーフコンポーネントのセクションで手順 4 を繰り返します。 コンポーネントで withMappable
ラッパー関数を使用します。
前に行ったように、ページ内のすべての子コンポーネントの AEM リソースタイプに MapTo
を適用します。
import { Page, MapTo, withMappable } from '@adobe/aem-react-editable-components';
import Text, { TextEditConfig } from './Text';
export default withMappable(Page);
MapTo('wknd-spa-react/components/text')(Text, TextEditConfig);
この例では、前に作成したラップされた AEMText
を含める代わりに、ラップされていない React テキストコンポーネントを使用しています。これは、コンポーネントがページ/コンテナの一部であってスタンドアローンではない場合、コンテナがコンポーネントのマッピングを再帰的に行い、オーサリング機能を有効にするので、子ごとの追加ラッパーが不応になるためです。
SPA で認証可能なページを追加するには、「認証可能なコンポーネントをページに追加」節を同じ手順に従います。 ただし、ここでは、itemPath
プロパティをスキップできます。
ページが編集可能であることを確認するには、「AEM でのテキストコンテンツの編集の確認」節と同じ手順に従います。
レイアウトコンテナと子テキストコンポーネントを持つ AEM でページを編集できるようになりました。
前の例では、既存の AEM コンテンツを持つ SPA にコンポーネントを追加しました。一方で、AEM でコンテンツは未作成だが、コンテンツの作成者が後から追加する必要がある場合もあります。これに対応するために、フロントエンド開発者は SPA 内の適切な場所にコンポーネントを追加できます。これらのコンポーネントは、AEM のエディターで開くとプレースホルダーを表示します。コンテンツの作成者がこれらのプレースホルダー内にコンテンツを追加すると、ノードが JCR 構造に作成され、コンテンツが保持されます。作成したコンポーネントでは、スタンドアロンのリーフコンポーネントと同じ操作のセットを使用できます。
この例では、以前に作成した AEMText
コンポーネントを再利用しています。WKND ホームページの既存のテキストコンポーネントの下に新しいテキストを追加します。コンポーネントの追加は、通常のリーフコンポーネントの場合と同じです。ただし、itemPath
は、新しいコンポーネントを追加する必要があるパスに更新できます。
新しいコンポーネントは、root/responsivegrid/text
にある既存のテキストの下に追加する必要があるので、新しいパスは root/responsivegrid/{itemName}
になります。
<AEMText
pagePath='/content/wknd-spa-react/us/en/home'
itemPath='root/responsivegrid/text_20' />
TestPage
コンポーネントは、仮想コンポーネントを追加すると次のようになります。
この機能を有効にするには、AEMText
コンポーネントの resourceType
が構成内に設定されていることを確認します。
「AEM でのテキストコンテンツの編集の確認」節の手順に従って、AEM に変更をデプロイできるようになりました。現在は存在しない text_20
ノードに対してプレースホルダーが表示されます。
コンテンツ作成者がこのコンポーネントを更新すると、新しい text_20
ノードが /content/wknd-spa-react/us/en/home
の root/responsivegrid/text_20
に作成されます。
仮想リーフコンポーネントを追加するための要件はいくつかあり、制限もいくつかあります。
pagePath
プロパティは、仮想コンポーネントを作成する場合に必須です。pagePath
のパスに指定されたページノードは、AEM プロジェクト内に存在する必要があります。itemPath
で指定する必要があります。itemPath='text_20'
を提供すると、新しいノードはページのすぐ下(/content/wknd-spa-react/us/en/home/jcr:content/text_20
)に作成されます。itemPath
経由で提供された場合に有効である必要があります。
text_20
を作成できるように、root/responsivegrid
が存在する必要があります。対応するコンテナが AEM に作成されていない場合でも、コンテナを追加する機能はサポートされます。概念とアプローチは仮想リーフコンポーネントと似ています。
フロントエンド開発者は、SPA 内の適切な場所にコンテナコンポーネントを追加できます。AEM のエディターでこれらのコンポーネントを開くとプレースホルダーが表示されます。次に、作成者はコンポーネントとそのコンテンツをコンテナに追加し、必要なノードを JCR 構造内に作成できます。
例えば、コンテナが既に /root/responsivegrid
に存在し、開発者が新しい子コンテナを追加したい場合は、次のようになります。
newContainer
はまだ AEM に存在しません。
このコンポーネントを含んだページを AEM で編集すると、コンテナの空のプレースホルダーが表示され、作成者はこのプレースホルダーにコンテンツを追加できます。
作成者がコンテナに子コンポーネントを追加すると、新しいコンテナノードが、対応する名前で JCR 構造内に作成されます。
作成者の必要に応じて、さらにコンポーネントとコンテンツをコンテナに追加できます。変更内容は保持されます。
仮想コンテナを追加するための要件はいくつかあり、制限もいくつかあります。
root/responsivegrid
が既に AEM コンテナに存在する場合は、パス root/responsivegrid/newContainer
を指定して新しいコンテナを作成できます。root/responsivegrid/newContainer/secondNewContainer
は使用できません。前の例に従った場合、外部 SPA は AEM 内で編集できるようになります。ただし、外部 SPA には、他にもカスタマイズできる要素があります。
デフォルトでは、React アプリケーションが要素 ID spa-root
の div
内でレンダリングされると想定しています。必要に応じて、これをカスタマイズできます。
例えば、要素 ID root
の div
内部にアプリケーションがレンダリングされる SPA があるとします。これは、3 つのファイルに反映する必要があります。
React アプリケーションの index.js
内(または ReactDOM.render()
が呼び出される場所)
React アプリケーションの index.html
内
AEM アプリケーションのページコンポーネント本体では、次の 2 つの手順に従います。
body.html
を作成します。body.html
ファイルの新しいルート要素を追加します。外部 React SPA アプリケーションに複数のページがある場合、レンダリングするページ/コンポーネントを決定する際にルーティングを使用できます。基本的な使用例は、現在アクティブな URL とルートに指定されたパスを一致させることです。このようなルーティング対応アプリケーションでの編集を可能にするには、対応するパスを AEM 固有の情報に合わせて変換する必要があります。
次の例では、2 つのページを含む単純な React アプリケーションを示します。レンダリングするページは、ルーターに提供されるパスとアクティブな URL とを一致させることで決定されます。例えば、mydomain.com/test
上にある場合、TestPage
がレンダリングされます。
この SPA の例で AEM 内での編集を有効にするには、次の手順が必要です。
AEM のルートとなるレベルを特定します。
wknd-spa-react/us/en
を SPA のルートとして使用します。つまり、そのパスより前のものはすべて AEM のページ/コンテンツのみです。必要なレベルで新しいページを作成します。
mydomain.com/test
です。test
がアプリのルートパスにあります。これは、AEM でページを作成する場合にも保持する必要があります。したがって、前の手順で定義したルートレベルで新しいページを作成できます。mydomain.com/test
の例では、新しく作成するページは /path/to/aem/root/test
にする必要があります。SPA ルーティング内のヘルパーを追加します。
/test
のパスを想定しているのに対し、AEM のアクティブパスは /wknd-spa-react/us/en/test
であるからです。AEM 固有の URL 部分を受け入れるには、SPA 側にヘルパーを追加する必要があります。@adobe/cq-spa-page-model-manager
が提供する toAEMPath
ヘルパーを使用できます。アプリケーションが AEM インスタンスで開かれる場合に、ルーティング用に指定されたパスを AEM 固有の部分を含めるように変換します。次のパラメーターを受け取ります。
AEM でのページの編集を確認します。
test
ページに移動します。これで、ページコンテンツがレンダリングされ、AEM コンポーネントが編集可能になります。RemotePage コンポーネントは、実装がここにあるような アセットマニフェストを提供することを想定しています。ただし、RemotePage コンポーネントは、React フレームワーク(および remote-page-next コンポーネントを介した Next.js)での動作のみがテストされているため、Angular などの他のフレームワークからのアプリケーションのリモート読み込みはサポートされていません。
AEM のコンテキストで SPA を理解するには、次の参照資料が役立ちます。