Adobe Experience Manager で AMP を使って心地よいユーザー エクスペリエンスを作成する
2019年12月23日月曜日
この記事は Jung von Matt 開発ディレクター、Matthias Rohmer による The AMP Blog の記事 "Creating Delightful User Experiences Using AMP On Adobe Experience Manager" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。
編集者のメモ: 以下のゲスト投稿は、Jung von Matt の開発ディレクター、Matthias Rohmer 氏によるものです
TL;DR: Jung von Matt は、Adobe Experience Manager で AMP を使用して、BMW によるすばらしいユーザー エクスペリエンスの実現をサポートしました。
クライアントのプロジェクトを実装する際、使用するテクノロジーを自由に選べるというのは、かなり珍しいことです。通常、エンタープライズ ソリューションを選んだクライアントは、その選択肢を補完しつつ、将来の成長を見込めるプロダクトやサービスを探します。
2017 年、BMW は自らのブランドのウェブサイト www.bmw.com を再構築するパートナー企業を探しているとき、先ほど述べた補完ソリューションを求めていました。ほぼすべての BMW のウェブサイトは Adobe Experience Manager(AEM)を使って構築されていたため、BMW が探していたのは、このようなハイエンド システムを扱えることに加え、AEM の機能を活用してメンテナンスしやすくパフォーマンスの高いウェブサイトを構築できるチームでした。
これは、BMW が既存のサイトで実現できなかった目標でした。既存サイトは、同じバックエンドを共有していながら、さまざまなフロントエンド フレームワークやライブラリが混在していました。私たちはプロセスのかなり早い段階で、このスタックに新しい空気を取り入れることを決めました。そして、全体を支えるフロントエンド テクノロジーとして、AMP を導入することを希望しました。私たちが頭を悩ませ始めたのはそこからです。最適な形で AMP と AEM を統合するには、どんな方法を使えばよいのでしょうか。ましてや、フロントエンド開発に関する前提事項があまりに多い CMS を使うのです。
AEM のビルトイン Rewriter パイプラインを活用すると、この `<link>` 要素を使ってスタイルシートを組み合わせ、通常の `<style amp-custom>` タグにすることができます。次のコードスニペット(かなり圧縮されています)を見ると、この変換がどのようなものになるか、大まかにわかっていただけるはずです。
すべての AEM コンポーネントにこのタイプの子要素を追加することで、依存先の AMP コンポーネントの情報を持たせます(上の例では amp-video)。ここでカスタム ノードタイプを使うメリットは、ページがレンダリングされる際に安全かつ迅速にノードに問い合わせることにより、必要な AMP コンポーネントを決めることができる点です。これは、次のようなコードになります。
つまり、このアプリケーションでは、同じドキュメントを 2 つのバージョンで提供できなければなりません。幸運にも、AEM ではこの機能を既に利用できます。そのためには、Sling セレクタを使います。
セレクタを作成するために必要なのは、並列する 2 つのテンプレートを実装することだけです。デフォルトで Sling エンジンが解決するものは、単に `html.html` と呼ばれています。もう 1 つには、セレクタの名前を付けます。今回のケースでは、`pwa.html` としました。これにより、すべての記事は brooklyn-beckham-car-photography.html から純粋な AMP 版としてアクセスするか、brooklyn-beckham-car-photography.pwa.html から PWA 機能でアクセスするかのどちらかになります。
この手法を用いることで、有効な AMP ページと PWA をそれぞれ独立して提供する方法を見つけました。しかし、どうすればユーザーはプログレッシブ ウェブアプリに到達できるのでしょうか。ここで、`amp-install-service-worker` が輝かしいデビューを飾ることになります。この AMP コンポーネントを使うと、ユーザーがいずれかの AMP キャッシュからいずれかのページを開いたときに、www.bmw.com が Service Worker をインストールします。それ以降、brooklyn-beckham-car-photography.html に向かうすべてのリクエストを brooklyn-beckham-car-photography.pwa.html に書き換えることができるようになります。これにより、気づかれることなくユーザー エクスペリエンスを向上させています。
私たちにとって、以上の 3 つが BMW の新しい国際マーケティング サイトを構築する上での主な課題でした。最終的には、既にクリエイティブな形で AEM と AMP に組み込まれている機能を使い、すべての課題を車輪の再発明を行うことなく解決できました。
AMP と Adobe は Bounteous とチームを組み、Adobe Experience Manager でさらに簡単に AMP サイトを構築できるようにしています。詳しく知りたい方や試してみたい方は、こちらをご覧ください。
執筆者: Jung von Matt 開発ディレクター、Matthias Rohmer
Reviewed by Chiko Shimizu - Developer Relations Team
編集者のメモ: 以下のゲスト投稿は、Jung von Matt の開発ディレクター、Matthias Rohmer 氏によるものです
TL;DR: Jung von Matt は、Adobe Experience Manager で AMP を使用して、BMW によるすばらしいユーザー エクスペリエンスの実現をサポートしました。
クライアントのプロジェクトを実装する際、使用するテクノロジーを自由に選べるというのは、かなり珍しいことです。通常、エンタープライズ ソリューションを選んだクライアントは、その選択肢を補完しつつ、将来の成長を見込めるプロダクトやサービスを探します。
2017 年、BMW は自らのブランドのウェブサイト www.bmw.com を再構築するパートナー企業を探しているとき、先ほど述べた補完ソリューションを求めていました。ほぼすべての BMW のウェブサイトは Adobe Experience Manager(AEM)を使って構築されていたため、BMW が探していたのは、このようなハイエンド システムを扱えることに加え、AEM の機能を活用してメンテナンスしやすくパフォーマンスの高いウェブサイトを構築できるチームでした。
これは、BMW が既存のサイトで実現できなかった目標でした。既存サイトは、同じバックエンドを共有していながら、さまざまなフロントエンド フレームワークやライブラリが混在していました。私たちはプロセスのかなり早い段階で、このスタックに新しい空気を取り入れることを決めました。そして、全体を支えるフロントエンド テクノロジーとして、AMP を導入することを希望しました。私たちが頭を悩ませ始めたのはそこからです。最適な形で AMP と AEM を統合するには、どんな方法を使えばよいのでしょうか。ましてや、フロントエンド開発に関する前提事項があまりに多い CMS を使うのです。
AMP と AEM を統合する際に解決すべき問題群
いくつかのリサーチを経て、AEM から有効な AMP ページを生成するためには、主に 3 つの課題を解決しなければならないことがわかりました。- AMP では、ドキュメントの CSS をすべて `<head>` 内にインラインで記述しなければならないので、AEM のビルトイン ClientLib 機能を使わずに CSS を生成する方法を探す必要があります。
- すべてのページを有効な AMP にするには、実際にページで使われる AMP コンポーネント用のリソースヒント(`<script async custom-element=”amp-carousel” src=”https://cdn.ampproject.org/v0/amp-carousel-0.2.js“></script>`)のみを生成するメカニズムが必要になります。
- 戻ってくる訪問者のためにプログレッシブ エンハンスメント(中心的なコンテンツから徐々に表示する戦略)を可能にするには、AEM が AMP ページと非 AMP ページの両方を同時にレンダリングできる必要があります。
AMP で使えるように CSS をインライン化する
AEM には、ページのスタイルを扱うかなり効率化されたアプローチが搭載されています。それを実現する ClientLib メカニズムは、ページに必要なすべての CSS をカテゴリと呼ばれるものに基づいて組み合わせてくれます。このカテゴリに基づいて、テンプレートの `<link>` タグを AEM に生成させます。このタグは、すべてのスタイルを含む生成済みのスタイルシートを指すことになります。AEM のビルトイン Rewriter パイプラインを活用すると、この `<link>` 要素を使ってスタイルシートを組み合わせ、通常の `<style amp-custom>` タグにすることができます。次のコードスニペット(かなり圧縮されています)を見ると、この変換がどのようなものになるか、大まかにわかっていただけるはずです。
StringBuilder styles = new StringBuilder();
boolean writeStyles = false;
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
if (localName.equalsIgnoreCase("link")) {
// If the element currently in queue is a link tag inspect it
String href = atts.getValue("href");
String rel = atts.getValue("rel");
if (rel.equalsIgnoreCase("stylesheet")) {
String css = "";
// TODO: Load the stylesheet from the JCR, store it with others loaded
// so far and append to styles
}
return;
}
if (localName.equalsIgnoreCase("style")) {
if (atts.getIndex("amp-custom")) {
writeStyles = true;
// TODO: Use this flag to emit all styles gathered in styles
// in the transformer's characters method
}
return;
}
contentHandler.startElement(uri, localName, qName, atts);
}
必要なリソースヒントのみを追加する
AMP の有効性を保証するために解決しなければならないもう 1 つの課題は、先ほどの `<script>` 要素を実際に必要とされるページにのみ追加することでした。これは、プロジェクトに次のカスタム ノードタイプを導入することで解決しました。<ampJS jcr:primaryType="bmw:ampJSResource" bmw:ampCustomElementTag="[amp-video]"/>
すべての AEM コンポーネントにこのタイプの子要素を追加することで、依存先の AMP コンポーネントの情報を持たせます(上の例では amp-video)。ここでカスタム ノードタイプを使うメリットは、ページがレンダリングされる際に安全かつ迅速にノードに問い合わせることにより、必要な AMP コンポーネントを決めることができる点です。これは、次のようなコードになります。
final PageManager pageManager = resource.getResourceResolver().adaptTo(PageManager.class);
final String currentPage = pageManager.getContainingPage(resource).getPath() + "/jcr:content";
final String query = String.format("SELECT * FROM [bmw:ampResourceHint] AS s WHERE ISDESCENDANTNODE(s,'%s')", currentPage);
final Iterator<Resource> result = resource.getResourceResolver().findResources(query, Query.JCR_SQL2);
while (result.hasNext()) {
Resource queryResource = result.next();
final String type = queryResource.getParent().getResourceType();
ValueMap properties = queryResource.adaptTo(ValueMap.class);
String[] usedComponents = properties.get("bmw:usedAmpComponents", String[].class);
if (usedComponents != null && usedComponents.length != 0) {
// TODO: Store all used components somewhere for later rendering
}
}
このロジック片は、`data-sly-use` 属性と `data-sly-repeat` を組み合わせることで、簡単に HTML テンプレートから呼び出すことができます。これにより、必要なすべてのリソースヒントをページの head に出力できます。AMP と合わせて PWA を提供する
www.bmw.com では、ユーザーの画面にサイトをできるだけ早く表示されるようにしたいと考えました。これを実現するために、すべての初回訪問者が AMP 版のページを受け取るようにします。同時に、AMP だけでは提供できないものの、PWA(これも AMP がベースになっています)なら提供できる機能も実装したいと考えました。つまり、このアプリケーションでは、同じドキュメントを 2 つのバージョンで提供できなければなりません。幸運にも、AEM ではこの機能を既に利用できます。そのためには、Sling セレクタを使います。
セレクタを作成するために必要なのは、並列する 2 つのテンプレートを実装することだけです。デフォルトで Sling エンジンが解決するものは、単に `html.html` と呼ばれています。もう 1 つには、セレクタの名前を付けます。今回のケースでは、`pwa.html` としました。これにより、すべての記事は brooklyn-beckham-car-photography.html から純粋な AMP 版としてアクセスするか、brooklyn-beckham-car-photography.pwa.html から PWA 機能でアクセスするかのどちらかになります。
この手法を用いることで、有効な AMP ページと PWA をそれぞれ独立して提供する方法を見つけました。しかし、どうすればユーザーはプログレッシブ ウェブアプリに到達できるのでしょうか。ここで、`amp-install-service-worker` が輝かしいデビューを飾ることになります。この AMP コンポーネントを使うと、ユーザーがいずれかの AMP キャッシュからいずれかのページを開いたときに、www.bmw.com が Service Worker をインストールします。それ以降、brooklyn-beckham-car-photography.html に向かうすべてのリクエストを brooklyn-beckham-car-photography.pwa.html に書き換えることができるようになります。これにより、気づかれることなくユーザー エクスペリエンスを向上させています。
私たちにとって、以上の 3 つが BMW の新しい国際マーケティング サイトを構築する上での主な課題でした。最終的には、既にクリエイティブな形で AEM と AMP に組み込まれている機能を使い、すべての課題を車輪の再発明を行うことなく解決できました。
AMP と Adobe は Bounteous とチームを組み、Adobe Experience Manager でさらに簡単に AMP サイトを構築できるようにしています。詳しく知りたい方や試してみたい方は、こちらをご覧ください。
執筆者: Jung von Matt 開発ディレクター、Matthias Rohmer
Reviewed by Chiko Shimizu - Developer Relations Team


