AEM 内での外部 SPA の編集 editing-external-spa-within-aem
外部 SPA と AEM の間でどのレベルの統合を行うかを決める際に、多くの場合、AEM 内で SPA を編集および表示できる必要があることを考慮してください。
概要 overview
このドキュメントでは、スタンドアロン SPA を AEM インスタンスにアップロードし、編集可能なコンテンツのセクションを追加し、オーサリングを有効にするための推奨手順について説明します。
前提条件 prerequisites
前提条件はシンプルです。
-
AEM のインスタンスがローカルで実行されていることを確認します。
-
AEM プロジェクトのアーキタイプを使用して、基本 AEM SPA プロジェクトを作成します。
- Forms は AEM プロジェクトの基盤を更新し、外部 SPA を含めます。
- このドキュメントの例では、WKND SPA プロジェクトの開始点を使用しています。
-
統合したい外部の React SPA を用意します。
SPA を AEM プロジェクトにアップロードする upload-spa-to-aem-project
まず、外部 SPA を AEM プロジェクトにアップロードする必要があります。
/ui.frontend
プロジェクトフォルダー内のsrc
を、React アプリケーションのsrc
フォルダーに置き換えます。- アプリの
package.json
に追加の依存関係があれば/ui.frontend/package.json
に含めます。- SPA SDK の依存関係が推奨バージョンであることを確認します。
/public
フォルダーにカスタマイズを含めます。- 追加されたインラインスクリプトまたはスタイルをすべて
/public/index.html
ファイルに含めます。
リモート SPA を設定する configure-remote-spa
これで外部 SPA が AEM プロジェクトの一部になったので、AEM 内で設定する必要があります。
Adobe SPA SDK パッケージを含める include-spa-sdk-packages
AEM SPA 機能の利用は、次の 3 つのパッケージに依存しています。
@adobe/aem-spa-page-model-manager
パッケージは、Model Manager を初期化し、AEM インスタンスからモデルを取得する API を提供します。その後、このモデルを使用して、@adobe/aem-react-editable-components
と @adobe/aem-spa-component-mapping
の API を使用して AEM コンポーネントをレンダリングできます。
インストール installation
次の npm
コマンドを実行して、必要なパッケージをインストールできるようにします。
npm install --save @adobe/aem-spa-component-mapping @adobe/aem-spa-page-model-manager @adobe/aem-react-editable-components
ModelManager の初期化 model-manager-initialization
アプリケーションがレンダリングされる前に、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
オブジェクト。
AEM 認証可能なリーフコンポーネント authorable-leaf-components
-
認証可能な React コンポーネントが作成される AEM コンポーネントを作成または識別します。この例では、WKND プロジェクトのテキストコンポーネントを使用しています。
-
SPA で単純な React テキストコンポーネントを作成します。この例では、次の内容の新しいファイル
Text.js
が作成されています。 -
設定オブジェクトを作成して、AEM 編集を有効にするために必要な属性を指定できるようにします。
resourceType
は、React コンポーネントを AEM コンポーネントにマップし、AEM エディターで開いたときに編集を有効にする場合に必須です。
-
ラッパー関数
withMappable
を使用します。このラッパー関数は、React コンポーネントを config で指定された AEM
resourceType
にマッピングし、AEM エディターで開いたときに編集機能を有効にします。スタンドアロンコンポーネントの場合は、特定のノードのモデルコンテンツも取得されます。note note NOTE この例では、コンポーネントに異なるバージョン(AEM でラップされた React コンポーネントとラップされていないコンポーネント)があります。コンポーネントを明示的に使用する場合は、ラップされたバージョンを使用する必要があります。コンポーネントがページの一部になっている場合は、SPA エディターで現在行われているように、デフォルトのコンポーネントを引き続き使用することができます。 -
コンポーネント内のコンテンツをレンダリングします。
テキストコンポーネントの JCR プロパティは、AEM では次のように表示されます。
これらの値は、作成された
AEMText
React コンポーネントにプロパティとして渡され、コンテンツのレンダリングに使用できます。code language-javascript 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 の設定が完了したときにコンポーネントがどのように表示されるかを示します。
code language-javascript 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>); };
note note NOTE この例では、既存のテキストコンポーネントに合わせて、レンダリングされたコンポーネントをさらにカスタマイズしています。AEM でのオーサリングとは関係ありません。
認証可能コンポーネントをページに追加する add-authorable-component-to-page
オーサリング可能な 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 でのテキストコンテンツの編集の確認 verify-text-edit
次に、実行中の AEM インスタンスでコンポーネントをテストします。
aem-guides-wknd-spa
ディレクトリから次の Maven コマンドを実行し、プロジェクトを構築して AEM にデプロイできるようにします。
mvn clean install -PautoInstallSinglePackage
- AEM インスタンスで、
http://<host>:<port>/editor.html/content/wknd-spa-react/us/en/home.html
に移動します。
AEMText
コンポーネントが、AEM 上で認証できるようになりました。
AEM 認証可能なページ aem-authorable-pages
-
SPA でのオーサリング用に追加するページを指定します。この例では
/content/wknd-spa-react/us/en/home.html
を使用しています。 -
オーサリング可能なページコンポーネントに対して、ファイル(例:
Page.js
)を作成します。@adobe/cq-react-editable-components
で提供されるページコンポーネントを使用します。 -
AEM オーサリング可能なリーフコンポーネントの節の手順 4 を繰り返します。コンポーネントで
withMappable
ラッパー関数を使用します。 -
前に行ったように、ページ内のすべての子コンポーネントの AEM リソースタイプに
MapTo
を適用します。code language-javascript 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);
note note NOTE この例では、以前に作成したラップされた AEMText
の代わりに、ラップされていない React テキストコンポーネントが使用されます。コンポーネントがページ/コンテナの一部で、単独ではない場合、コンテナはコンポーネントの再帰的なマッピングを処理するからです。また、子ごとにオーサリング機能を有効にしたり、追加のラッパーを使用する必要はありません。 -
SPA でオーサリング可能なページを追加するには、オーサリング可能なコンポーネントをページに追加の節と同じ手順に従います。ここでは、
itemPath
プロパティをスキップできます。
AEM でのページコンテンツの確認 verify-page-content
ページが編集可能であることを確認するには、AEM でのテキストコンテンツの編集の確認の節と同じ手順に従います。
レイアウトコンテナと子テキストコンポーネントを持つ AEM でページを編集できるようになりました。
仮想リーフコンポーネント virtual-leaf-components
前の例では、既存の 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
に作成されます。
要件と制限事項 limitations
仮想リーフコンポーネントを追加するには、いくつかの要件と制限があります。
pagePath
プロパティは、仮想コンポーネントを作成する場合に必須です。pagePath
のパスに指定されたページノードは、AEM プロジェクト内に存在する必要があります。- 作成するノードの名前は、
itemPath
で指定する必要があります。 - コンポーネントは任意のレベルで作成できます。
- 前の例で
itemPath='text_20'
を提供すると、新しいノードはページのすぐ下(/content/wknd-spa-react/us/en/home/jcr:content/text_20
)に作成されます。
- 前の例で
- 新しいノードが作成されるノードへのパスは、
itemPath
経由で提供された場合に有効である必要があります。- この例では、新しいノード
text_20
を作成できるように、root/responsivegrid
が存在する必要があります。
- この例では、新しいノード
- リーフコンポーネントの作成のみがサポートされます。仮想コンテナと仮想ページは、今後のバージョンでサポートされる予定です。
仮想コンテナ virtual-containers
対応するコンテナが AEM に作成されていない場合でも、コンテナを追加する機能はサポートされます。概念とアプローチは仮想リーフコンポーネントと似ています。
フロントエンド開発者は、SPA 内の適切な場所にコンテナコンポーネントを追加できます。AEM のエディターでこれらのコンポーネントを開くとプレースホルダーが表示されます。次に、作成者はコンポーネントとそのコンテンツをコンテナに追加し、必要なノードを JCR 構造内に作成できます。
例えば、コンテナが既に /root/responsivegrid
に存在し、開発者が新しい子コンテナを追加したい場合は、次のようになります。
newContainer
はまだ AEM に存在しません。
このコンポーネントを含んだページを AEM で編集すると、コンテナの空のプレースホルダーが表示され、作成者はこのプレースホルダーにコンテンツを追加できます。
作成者がコンテナに子コンポーネントを追加すると、新しいコンテナノードが、対応する名前で JCR 構造内に作成されます。
作成者の必要に応じて、さらにコンポーネントとコンテンツをコンテナに追加できます。変更内容は保持されます。
要件と制限事項 container-limitations
仮想コンテナを追加する場合は、いくつかの要件と制限があります。
-
追加できるコンポーネントを決定するためのポリシーは、親コンテナから継承されます。
-
作成するコンテナの直近の親が AEM に存在している必要があります。
- コンテナ
root/responsivegrid
が AEM コンテナに存在する場合は、パスroot/responsivegrid/newContainer
を指定して新しいコンテナを作成できます。 - ただし、
root/responsivegrid/newContainer/secondNewContainer
は使用できません。
- コンテナ
-
一度に 1 つの新しいコンポーネントレベルのみ作成できます。
追加のカスタマイズ additional-customizations
前の例に従った場合、外部 SPA は AEM 内で編集できるようになります。ただし、外部 SPA には、他にもカスタマイズできる要素があります。
ルートノード ID root-node-id
デフォルトでは、React アプリケーションが要素 ID spa-root
の div
内でレンダリングされると想定できます。必要に応じて、この構文をカスタマイズできます。
例えば、要素 ID root
の div
内部にアプリケーションがレンダリングされる SPA があるとします。この構文は、3 つのファイルに反映する必要があります。
-
React アプリケーションの
index.js
内(またはReactDOM.render()
が呼び出される場所) -
React アプリケーションの
index.html
内 -
AEM アプリケーションのページコンポーネント本体では、次の 2 つの手順に従います。
- ページコンポーネント用に
body.html
を作成します。
- 新しい
body.html
ファイルにルート要素を追加します。
- ページコンポーネント用に
ルーティングを使用したリアクション SPA の編集 editing-react-spa-with-routing
外部 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 ルーティング内のヘルパーを追加します。
- 作成されたページでは、AEM で期待されたコンテンツをまだレンダリングできません。これは、ルーターが
/test
のパスを想定しているのに対し、AEM のアクティブパスは/wknd-spa-react/us/en/test
であるからです。AEM 固有の URL 部分を受け入れるには、SPA 側にヘルパーを追加する必要があります。
-
@adobe/cq-spa-page-model-manager
が提供するtoAEMPath
ヘルパーを使用できます。アプリケーションが AEM インスタンスで開かれる場合に、ルーティング用に指定されたパスを AEM 固有の部分を含めるように変換します。次のパラメーターを受け取ります。- ルーティングに必要なパス
- SPA が編集される AEM インスタンスのオリジン URL
- 最初の手順で決定した AEM のプロジェクトルート
-
これらの値は、環境変数として設定でき、より柔軟に設定できます。
- 作成されたページでは、AEM で期待されたコンテンツをまだレンダリングできません。これは、ルーターが
-
AEM でのページの編集を確認します。
- プロジェクトを AEM にデプロイし、作成した
test
ページに移動します。これで、ページコンテンツがレンダリングされ、AEM コンポーネントが編集可能になります。
- プロジェクトを AEM にデプロイし、作成した
フレームワークの制限 framework-limitations
RemotePage コンポーネントでは、実装でアセットマニフェストが指定されることを想定しています。アセットマニフェストの例については、GitHub の webpack-manifest-plugin を参照してください。ただし、RemotePage コンポーネントは React フレームワーク(および remote-page-next コンポーネントを介した Next.js)で動作するようにのみテストされているので、Angular など他のフレームワークからのアプリケーションのリモート読み込みはサポートされていません。
その他のリソース additional-resources
AEM のコンテキストで SPA を理解するには、次の参照資料が役立ちます。