ヘッドレスOracle Content ManagementによるReactでの最小サイトの作成

イントロダクション

Reactは、Webアプリケーションの構築に広く使用されているJavaScriptフレームワークです。

ReactアプリケーションでOracle Content Managementコンテンツを使用するには、GitHubのオープンソース・リポジトリとして使用可能なReact最小サンプルを使用できます。

このチュートリアルでは、Oracle Content ManagementをヘッドレスCMSおよびJavaScriptのコンテンツ配信用のソフトウェア開発キット(SDK)として活用することで、Reactでシンプルな最小サイトを構築します。Oracle Content Managementには、すべての公開済コンテンツおよびすべてのアセット・タイプに対するGraphQLのサポートも含まれています。このReactのサンプルは、GitHubにあります。

このチュートリアルは、次の3つのタスクで構成されています。

  1. Oracle Content Managementの準備
  2. Reactで最小限のサイトを構築
  3. デプロイメント用のアプリケーションの準備

前提条件

このチュートリアルを進める前に、まず次の情報をお読みください。

このチュートリアルに従うには、次が必要です:

構築対象

Reactの最小化により、Oracle Content Managementリポジトリからイメージやその他のコンテンツを簡単に取得できます。

作成している内容を確認するには、Oracle Content Managementのコンテンツを使用する基本的なReact最小サイトであるチュートリアルの最終状態を次に示します。

https://headless.mycontentdemo.com/samples/oce-react-minimal-sample

このチュートリアルの最後にあるホーム・ページは次のようになります。

この図は、React Minimumサイトのランディング・ページを示しています。

「お問い合わせ」ページは次のチュートリアルの最後に表示されます。

この図は、React Minimumサイトの「問合せ先」ページを示しています。

個人ページは次のチュートリアルの最後に表示されます。

この図は、React Minimumサイトの「問合せ先」ページを示しています。

続行するには、Oracle Content Managementのアクティブなサブスクリプションを持ち、コンテンツ管理者ロールでログインする必要があります。

タスク1: Oracle Content Managementの準備

Oracle Content Managementインスタンスがまだない場合は、クイック・スタートを参照して、Oracle Cloudへの登録、Oracle Content Managementインスタンスのプロビジョニング、およびOracle Content ManagementをヘッドレスCMSとして構成する方法を学習します。

このチュートリアルでは、コンテンツ・モデルを作成する必要があります。使用可能なダウンロード可能なアセット・パックがあり、空のリポジトリにコンテンツ・タイプおよび関連付けられたコンテンツを入力します。

Oracle Content Managementを準備するには:

  1. チャネルおよびアセット・リポジトリを作成します
  2. 次の2つの方法のいずれかを使用して、コンテンツ・モデルを作成します:

チャネルおよびアセット・リポジトリの作成

コンテンツを公開するには、まずOracle Content Managementでチャネルおよびアセット・リポジトリを作成する必要があります。

Oracle Content Managementでチャネルおよびアセット・リポジトリを作成するには:

  1. Oracle Content Management Webインタフェースに管理者としてログインします。

  2. 左側のナビゲーション・メニューで「コンテンツ」を選択し、ページ・ヘッダーの選択リストから「チャネルの公開」を選択します。

    この図は、「コンテンツ」ページ・ヘッダーのドロップダウン・メニューで選択された「公開チャネル」オプションを示しています。

  3. 右上隅にある「Create」をクリックして、新しいチャネルを作成します。このチュートリアルの目的でチャネルにOCEMinimalChannelという名前を付け、アクセスを公開したままにします。「保存」をクリックしてチャネルを作成します。

    この図は、「チャネル名」フィールドにOCEMinimalChannelがある公開チャネル定義パネルを示しています。

  4. 左側のナビゲーション・メニューで「コンテンツ」を選択し、ページ・ヘッダーの選択リストから「リポジトリ」を選択します。

    この図は、「コンテンツ」ページ・ヘッダーのドロップダウン・メニューで選択された「リポジトリ」オプションを示しています。

  5. 右上隅にある「作成」をクリックして、新しいアセット・リポジトリを作成します。このチュートリアルの目的で、アセット・リポジトリにOCEMinimalRepositoryという名前を付けます。

    この図は、リポジトリ名フィールドにOCEMinimalRepositoryがあるリポジトリ定義パネルを示しています。

  6. 「公開チャネル」フィールドで、OCEMinimalChannelチャネルを選択して、OCEMinimalRepositoryリポジトリ内のコンテンツをOCEMinimalChannelチャネルに公開できることをOracle Content Managementに示します。終了したら、「Save」をクリックします。

    この図は、「公開チャネル」フィールドにOCEMinimalChannelがあるリポジトリ定義パネルを示しています。

コンテンツ・モデルの作成

次のステップでは、コンテンツ・モデルを作成します。次の2つの方法のいずれかを使用できます。

Oracle Content Managementサンプル資産パックのインポート

このチュートリアルに必要なすべてのコンテンツ・タイプおよびアセットを含む事前構成済のOracle Content Managementサンプル・アセット・パックをダウンロードできます。必要に応じて、サンプル・アセット・パックをダウンロードするのではなく、独自のコンテンツ・モデルを作成することもできます。

このチュートリアルで使用しているコンテンツのコピーは、Oracle Content Managementサンプル資産パックからアップロードできます。これにより、コンテンツ・タイプを試し、コンテンツを変更できます。Oracle Content Managementサンプル・アセット・パックをインポートする場合は、アセット・パック・アーカイブOCESamplesAssetPack.zipをダウンロードし、選択したディレクトリに抽出します:

  1. Oracle Content Managementのダウンロード・ページからOracle Content ManagementのSamples Asset Pack (OCESamplesAssetPack.zip)をダウンロードします。ダウンロードしたzipファイルをコンピュータ上の場所に抽出します。抽出後、この場所にはOCEMinimal_data.zipというファイルが含まれます。

  2. Oracle Content Management Webインタフェースに管理者としてログインします。

  3. 左側のナビゲーション・メニューで「コンテンツ」を選択し、ページ・ヘッダーの選択リストから「リポジトリ」を選択します。次に、OCEMinimalRepositoryを選択し、上部アクション・バーの「コンテンツのインポート」ボタンをクリックします。

    この図は、OCEMinimalRepositoryアイテムが選択された「リポジトリ」ページを示しています。

  4. ローカル・コンピュータから「ドキュメント」フォルダにOCEMinimal_data.zipをアップロードします。

    この図は、OCEMinimal_data.zipファイルのアップロード確認画面を示しています。

  5. アップロードしたら、OCEMinimal_data.zipを選択し、「OK」をクリックしてコンテンツをアセット・リポジトリにインポートします。

    この図は、「OK」ボタンが有効になっている、選択したOCEMinimal_data.zipファイルを示しています。

  6. コンテンツが正常にインポートされたら、「アセット」ページに移動し、OCEMinimalRepositoryリポジトリを開きます。すべての関連イメージおよびコンテンツ項目がアセット・リポジトリに追加されたことがわかります。

    この図は、インポートされたすべてのアセットを含むOCEMinimalRepositoryリポジトリを示しています。

  7. 左上の「すべて選択」をクリックし、「公開」をクリックして、前に作成した公開チャネルOCEGettingStartedChannelにインポートされたすべてのアセットを追加します。

    この図は、すべてのアセットが選択され、アクション・バーに「公開」オプションが表示されているOCEMinimalRepositoryリポジトリを示しています。

  8. 公開する前に、すべてのアセットを検証する必要があります。最初にOCEMinimalChannelを選択したチャネルとして追加し、「検証」ボタンをクリックします。

    この図は、「チャネル」フィールドにOCEMinimalChannelチャネルが追加され、検証するすべてのアセットおよび「検証」ボタンが有効になっている「検証結果」ページを示しています。

  9. アセットの検証後、右上隅の「公開」ボタンをクリックして、選択したチャネルにすべてのアセットを公開できます。

    この図は、「チャネル」フィールドにOCEMinimalChannelチャネルが追加され、すべてのアセットが検証され、「公開」ボタンが有効になっている「検証結果」ページを示しています。

完了すると、「アセット」ページで、すべてのアセットが公開されていることがわかります。(アセット名の上のアイコンで確認できます。)

この図は、すべてのアセットが公開されている「アセット」ページを示しています。

Oracle Content Managementサンプル資産パックをインポートした後、Reactでの最小サイトの構築を開始できます。

独自のコンテンツ・モデルの作成

Oracle Content Managementサンプル・アセット・パックのインポートのかわりに、独自のコンテンツ・モデルを作成することもできます。

このチュートリアルでは、このサンプルのメイン・コンテンツ・タイプとして'MinimalMain'というコンテンツ・タイプを使用しています。このコンテンツ・タイプは、ヘッダーとフッターのロゴ、およびナビゲーションに含めるページのリストで構成されます。

この図は、「最小」サンプルのホーム・ページを示しています。

コンテンツ・モデルのコンテンツ・タイプを作成するには:

  1. Oracle Content Management Webインタフェースに管理者としてログインします。
  2. 左側のナビゲーション・メニューで「コンテンツ」を選択し、ページ・ヘッダーの選択リストから「アセット・タイプ」を選択します。
  3. 右上隅の「作成」をクリックします。
  4. (デジタル・アセット・タイプではない)コンテンツ・タイプを作成することを選択します。必要なすべてのコンテンツ・タイプについて、これを繰り返します。

この図は、Oracle Content Management Webインタフェースの「アセット・タイプの作成」ダイアログを示しています。

それぞれ独自のフィールド・セットを持つ5つのコンテンツ・タイプを作成します。

最初のコンテンツ・タイプMinimalMainには、次のフィールドが必要です。

表示名 フィールド・タイプ 必須 マシン名
headerLogo 単一値メディア・フィールド headerLogo
footerLogo 単一値メディア・フィールド footerLogo
ページ 複数値参照フィールド ページ

MinimalMainコンテンツ・タイプ定義は次のようになります。

この図は、コンテンツ・タイプ'MinimalMain'の定義を示しています。次のデータ・フィールドが含まれます: headerLogo、footerLogo、ページ。

2番目のコンテンツ・タイプMinimalPageには、次のフィールドが必要です。

表示名 フィールド・タイプ 必須 マシン名
セクション 複数値参照フィールド セクション

MinimalPageコンテンツ・タイプは次のようになります。

この図は、コンテンツ・タイプ'MinimalPage'の定義を示しています。このデータ・フィールド: セクションが含まれます。

3番目のコンテンツ・タイプMinimalSectionには、次のフィールドが必要です。

表示名 フィールド・タイプ 必須 マシン名
タイプで打つ 単一値テキスト・フィールド X タイプで打つ
ヘディング 単一値テキスト・フィールド ヘディング
死体 単一値の大きいテキスト・フィールド 死体
画像 単一値イメージ・フィールド イメージ
アクション 単一値の埋込みコンテンツ・フィールド アクション

MinimalSectionコンテンツ・タイプは次のようになります。

この図は、コンテンツ・タイプ'MinimalSection'の定義を示しています。これには、タイプ、見出し、本文、イメージ、アクションのデータ・フィールドが含まれます。

4番目のコンテンツ・タイプPeoplePageには、次のフィールドが必要です。

表示名 フィールド・タイプ 必須 マシン名
お知らせ 単一値参照フィールド お知らせ
人々 複数値参照フィールド 人々

5番目と最後のコンテンツ・タイプ「個人」は、次のフィールドを含むカスタム・デジタル・アセットです:

表示名 フィールド・タイプ 必須 マシン名
fullName 単一値テキスト・フィールド X fullName
標題 単一値テキスト・フィールド 標題
ヨウ素 単一値の大きいテキスト・フィールド ヨウ素

コンテンツ・タイプを作成したら、前に作成したリポジトリOCEMinimalRepositoryに次のコンテンツ・タイプを追加できます。

  1. Oracle Content Management Webインタフェースに管理者としてログインします。
  2. OCEMinimalRepositoryに移動します。
  3. リポジトリを編集し、「アセット・タイプ」で、新しく作成された5つのコンテンツ・タイプすべてを指定します。「保存」ボタンをクリックして変更を保存します。

この図は、Oracle Content Managementの「リポジトリの編集」ページを示しており、新しく作成されたコンテンツ・タイプがOCEMinimalRepositoryリポジトリに関連付けられています。

コンテンツ・タイプをリポジトリに追加した後、「アセット」ページでOCEMinimalRepositoryリポジトリを開き、すべてのコンテンツ・タイプのコンテンツ項目の作成を開始できます。

このイメージは、Oracle Content Management Webインタフェースの「アセット」ページのコンテンツ・アイテムを示しています。コレクション、チャネル、言語、タイプ、コンテンツ・アイテム選択およびステータスのオプションは左側にあります。

タスク2: Reactでの最小サイトの作成

サーバー側のレンダリングされたReactアプリケーションでOracle Content Managementコンテンツを使用するには、GitHubのオープンソース・リポジトリとして使用できるReact Minimum Siteサンプルを使用します。

ノート: Reactサンプルの使用はオプションであり、このチュートリアルで使用するとすぐに作業を開始できます。独自のReactアプリケーションを作成することもできます。

Reactで最小限のサイトを構築するには:

  1. サンプル・リポジトリのクローニングおよび依存性のインストール
  2. Reactアプリケーションの構成
  3. Oracle Content Management Content SDKの操作
  4. Content SDKを使用したコンテンツのフェッチ
  5. GraphQLを使用して、Peopleページを作成します

サンプルリポジトリのクローニングと依存関係のインストール

React Minimum Siteサンプルは、GitHubのオープン・ソース・リポジトリとして使用できます。

まず、GitHubからローカル・コンピュータにサンプルをクローニングし、ディレクトリをリポジトリ・ルートに変更する必要があります。

git clone https://github.com/oracle/oce-react-minimal-sample.git
cd oce-react-minimal-sample

コード・ベースを作成したので、アプリケーションの依存関係をダウンロードする必要があります。ルート・ディレクトリから次のコマンドを実行します。

npm install

Reactアプリケーションの構成

このReact最小サイト・サンプルでは、Oracle Content Management Content SDK (および他のリクエスト)が正しいチャネル・トークンで正しいインスタンスURLおよびAPIバージョンをターゲットにできるように、いくつかの情報を構成する必要があります。これらの値は、新しい配信クライアントをインスタンス化するためにsrc/scripts/server-config-utils.jsで使用されます。

このアプリケーションは、クライアントおよびサーバー・アプリケーションのバンドル時にWebpackによって読み取られる.envファイルを使用します。webpack.DefinePluginを使用すると、.envファイルから読み取られたすべての値をアプリケーションの任意の場所で使用できます。

.envファイルをテキスト・エディタで開きます。次のようなものが表示されます。

# The connection details for the Oracle Content Management server to be used for this application
SERVER_URL=https://samples.mycontentdemo.com
API_VERSION=v1.1
CHANNEL_TOKEN=ba0efff9c021422cb134c2fd5daf6015

各キーと値のペアを変更して、インスタンスURL、ターゲットにするAPIバージョンおよび公開チャネルに関連付けられたチャネル・トークンを反映します。このチュートリアルのチャネルは、OCEMinimalChannelです。

Oracle Content Management Content SDKの操作

Oracle Content Managementは、アプリケーションのコンテンツの発見や使用に役立つSDKを提供します。SDKはNPMモジュールとして公開され、プロジェクトはGitHubでホストされています。

SDKの詳細はここを参照してください。

SDKは、このプロジェクトのランタイム依存関係としてpackage.jsonファイルに登録されています。

Content SDKを使用したコンテンツのフェッチ

Reactアプリケーションでレンダリングできるように、Content SDKを使用してコンテンツをフェッチできるようになりました。

Content SDKでは、DeliveryClientオブジェクトを使用してエンドポイントを指定します。そのクライアントオブジェクトを使用してすべてのリクエストを作成できます。

src/scriptsフォルダには、Content SDKを使用してOracle Content Managementからデータを取得するためのコードが含まれます。

src/scripts/server-config-utils.jsファイルは、Content SDKをインポートし、.envで指定された構成を使用して配信クライアントを作成します。

次のコマンドは、SDKをインポートします:

import { createDeliveryClient, createPreviewClient } from '@oracle/content-management-sdk';

次のコマンドは、配信クライアントを作成します:

return createDeliveryClient(serverconfig);

src/scripts/services.jsファイルには、このReact最小アプリケーションのデータを取得するための関数が含まれています。

fetchOceMinimalMain()メソッドは、最小メインのスラグでコンテンツ・タイプMinimalMainを取得します。

export async function fetchOceMinimalMain() {
  const data = await getItem('minimalmaingraphql', 'fields.headerlogo,fields.footerlogo,fields.pages');
  if (!data.hasError) {
    const { fields } = data;
    const { headerlogo, footerlogo } = fields;
    // Extract the sourceset for the headerImage and footerImage and put it back in the data
    data.headerRenditionURLs = getSourceSet(headerlogo);
    data.footerRenditionURLs = getSourceSet(footerlogo);
  }
  return data;
}

ノート:前述の問合せは、タイプが「People」ページの「People」ページを含むスラグ「minimalmaingraphql」のアセットに対するものです。「People」ページなしで最小サイトを作成するには、かわりにアセット・パックにスラグ「minimalmain」が含まれるアセットを使用できます。

イメージをレンダリングする場合、services.jsには、アセットのレンディションから構築されたアセットのソースセットを取得するためのヘルパー・メソッドが用意されています。

function getSourceSet(asset) {
  const urls = {};
  urls.srcset = '';
  urls.jpgSrcset = '';
  if (asset.fields && asset.fields.renditions) {
    asset.fields.renditions.forEach((rendition) => {
      addRendition(urls, rendition, 'jpg');
      addRendition(urls, rendition, 'webp');
    });
  }
  // add the native rendition to the srcset as well
  urls.srcset += `${asset.fields.native.links[0].href} ${asset.fields.metadata.width}w`;
  urls.native = asset.fields.native.links[0].href;
  urls.width = asset.fields.metadata.width;
  urls.height = asset.fields.metadata.height;
  return urls;
}

fetchPage()メソッドは、前の問合せから取得したページのスラグ値を使用してコンテンツ・タイプMinimalPageを取得します。

export async function fetchPage(pageslug) {
  // Get the page details
  const page = await getItem(pageslug, 'fields.sections');
  return page;
}

getRenditionURLs()メソッドは、そのイメージのIDを使用してセクションに定義されている可能性のあるイメージのレンディションURLを取得します。このコールはクライアント側で実行されます。

export function getRenditionURLs(identifier) {
  const client = getClient();
  return client.getItem({
    id: identifier,
    expand: 'fields.renditions',
  }).then((asset) => getSourceSet(asset))
    .catch((error) => logError('Fetching Rendition URLs failed', error));
}

GraphQLを使用した「ユーザー」ページの構成

package.jsonのApolloクライアントを使用して、GraphQLをReactに統合し、src/scripts/services-graphql.jsのfetchPeopleメソッドを使用してコンテンツ・サーバーにGraphQLコールを行います。

Oracle Content ManagementにGraphQLサポートを含める方法の詳細は、ReactおよびOracle Content ManagementでのGraphQLの使用チュートリアルを参照してください。

データ問合せができたので、Reactコンポーネントでレスポンスをレンダリングできます。

クライアント側のレンダリングとサーバー側のレンダリング

クライアント側レンダリング(CSR)では、クライアントはJavaScriptを使用してWebページのコンテンツを構築およびレンダリングします。サーバー側レンダリング(SSR)では、ページがサーバーに構築され、Webページがクライアントに返されます。

クライアント側レンダリングでWebページをサーバーからリクエストすると、返されるHTMLドキュメントにはスケルトンHTMLが含まれ、実際のコンテンツは含まれません。これには、クライアントがサーバーからリクエストするJavaScriptバンドルへの参照が含まれます。このバンドルを受信すると、クライアントはJavaScriptを実行し、Webページに移入します。クライアントがJavaScriptの実行を終了するまで、すべてのユーザーに表示されるWebページは空白です。クライアント側レンダリング・アプリケーションの1つの欠点は、一部のWebクローラがサイトに索引付けするときに、索引付けする実際のコンテンツがないことです。

サーバー側レンダリング(SSR)では、ページがサーバーに構築され、Webページがクライアントに返されます。この利点は、WebクローラがWebページのコンテンツを索引付けできることです。

最小サイト申請フローの反応

React Minimum Siteアプリケーションのフローは次のとおりです。

  1. クライアントは、指定されたルートについてサーバーにリクエストします。
  2. Expressサーバーがリクエストを受信します。
  3. Expressサーバーでは、次のタスクが実行されます。
    1. 特定のルートに対してレンダリングされるコンポーネントを決定し、コンポーネントのfetchInitialData関数をコールして、そのコンポーネントのすべてのデータを取得します。
    2. レンダリングするすべてのコンテンツの文字列が作成されます。(各コンポーネントは、HTMLマークアップを生成するようにレンダリングするよう求められます。)
    3. これにより、次の項目を含むHTMLドキュメントが作成されます。
      • レンダリングするコンテンツの文字列
      • スタイルシートへのリンク(該当する場合)
      • クライアントが必要とするクライアントbundle.jsを含むスクリプト・タグ
      • JSONとしてシリアライズされたすべてのコンポーネントから取得されたデータ
    4. 次に、サーバーはHTMLをクライアントに返します。
  4. クライアントはHTMLを受信してレンダリングします。完全に構成されたWebページが表示されます。
  5. HTMLのJavaScriptは、クライアント上のWebブラウザ・ウィンドウにデータを格納します。
  6. クライアントは、サーバーからクライアントbundle.jsファイルをリクエストします。受信後、クライアントはバンドルでJavaScriptを実行します。
    • HTMLをハイドレートし、イベント・リスナーなどのクライアント側のJavaScriptに追加します。
    • レンダリングされる各コンポーネントは、そのデータがウィンドウに保存されている場合に表示されます。その場合、そのデータが使用されます。それ以外の場合、コンポーネントはContent SDKを介してOracle Content Managementサーバーにリクエストすることで、必要なデータを取得します。
  7. HTMLドキュメントにスタイル・シートが含まれている場合、クライアントはスタイル・シートをリクエストします。

Webページのソースを表示すると、HTML内のすべてのコンテンツが表示され、ページがサーバーにレンダリングされたことが示されます。

ノート:このサンプル・アプリケーションは、ルート・コンポーネント内のデータを取得し、そのデータを必要な子コンポーネントに渡します。もう1つの方法は、データをストアに配置するReduxなどの状態管理ツールを使用することであり、どのコンポーネントもそのストアからデータをリクエストできます。

サーバー側のExpressサーバーとレンダリング

サーバー・アプリケーションは、Expressサーバーを使用してリクエストを受信し、Reactアプリケーション・インスタンスを生成し、HTMLページを生成してレスポンスを返します。

Expressサーバー・ファイルは、src/server/server.jsにあります。

Expressサーバーはすべてのリクエストを受け入れ、Reactのreact-router-dom matchPath()を使用して、指定したルートに対してレンダリングされるコンポーネントを取得します。これにより、そのコンポーネントのfetchInitialDataメソッドをコールしてそのコンポーネントのデータを取得し、promiseを返します。Promiseが実行され、データを含むコンテキスト・オブジェクトが作成されます。次に、HTMLコンテンツをクライアントに返す前に、レンダラがコールされてHTMLページが生成されます。

server.get('*', (req, res) => {
  // matchRoutes will return all the components which will be rendered as per the request route.
  // call "fetchInitialData" on each of those components (if the component has such a method),
  // and build up an array of pending network calls for all the data required for the components
  // which will be rendered.
  const promises = matchRoutes(Routes, req.path).map(({ route }) => (
    route.fetchInitialData ? route.fetchInitialData(req) : null));

  // Execute all promises at the same time to get all the data, once its all been obtained
  // render the HTML to the client by delgating to the "renderer" method
  Promise.all(promises).then((data) => {
    // this context object gets passed into the renderer, which in turn passes it
    // to the StaticRouter. The StaticRouter passes it to any component which is called
    // as the "staticContext" prop.
    const context = { data };

    // get the content to return to the client
    const content = renderer(req, context);

    // if the route requested was not found, the content object will have its "notFound"
    // property set, therefore we need to change the response code to a 404, not found
    if (context.notFound) {
      res.status(404);
    }

    if (context.url) {
      // If a redirect was set using a Redirect component do that
      res.redirect(301, context.url);
    } else {
      // send the response
      res.send(content);
    }
  });
});

レンダラはsrc/server/renderer.jsxにあり、Reactのreact-dom/server renderToString()を使用して、レンダリングされるすべてのコンテンツの文字列を取得します。

// generate the HTML content for this application
const content = renderToString(
  <StaticRouter context={context} location={req.path} basename={process.env.BASE_URL}>
    <div>{renderRoutes(Routes)}</div>
  </StaticRouter>,
);

レンダラに渡されるコンテキスト・オブジェクトは、サーバー側のルーターStaticRouterに渡されます。サーバー側のレンダリング中に、コンポーネントによってコンポーネントのプロパティからデータを取得できます。

this.props.staticContext.data

レンダラは、Reactコンテンツ、シリアライズされたデータ、およびクライアントで実行するJavaScriptバンドルへの参照を含むHTMLマークアップを返します。

<body>
  <div id="root">${content}</div>
  <script>
    window.INITIAL_DATA = ${serialize(context.data)}
  </script>
  <script src="${clientBundleFile}"></script>
</body>

クライアントがHTMLを受信すると、データがウィンドウで使用可能になり、クライアントはサーバーからクライアント・バンドルを要求します。

クライアント側のレンダリング

クライアント側のレンダリング・コードは、src/client/main.jsにあります。このコードは、WebページのすべてのHTMLを経由し、クライアント側のJavaScriptコードを追加します。

このプロセスをハイドレーションと呼びます。

ReactDOM.hydrate(
  <BrowserRouter basename={process.env.BASE_URL}>
    <div>{renderRoutes(Routes)}</div>
  </BrowserRouter>,
  document.querySelector('#root'),
);

Reactコンポーネント

Reactは、JSX (JavaScriptへのHTML形式の構文拡張)と呼ばれるテクノロジを使用して、コンテンツをレンダリングします。Oracle Content Managementからデータをレンダリングするために純粋なJavaScriptを記述できますが、JSXを使用することを強くお薦めします。

最小限のサイト・アプリケーションでは、各ページが多数の小さなコンポーネントに分割されます。

次のいくつかのセクションでは、Reactが各コンポーネントでアプリケーションをどのようにレンダリングするかの概要を説明します。

IS_BROWSER変数

Webpackは、クライアントおよびサーバー・コードをバンドルするために使用します。各バンドルの作成方法をWebpackに指示する構成ファイルがあります。

クライアント・バンドルの構成ファイルwebpack.client.config.jsを開きます。ファイルの下部に、アプリケーションがブラウザで実行されていることを示す変数が設定されます。

new webpack.DefinePlugin({
  'process.env.IS_BROWSER': true,
}),

サーバー・バンドルの構成ファイルwebpack.server.config.jsを開きます。ファイルの下部に、アプリケーションがブラウザで実行されていないことを示す同じ変数が設定されます。IS_BROWSER変数には、Reactアプリケーション・コードの任意の場所からアクセスして、アプリケーションがサーバーまたはクライアントでレンダリングされているかどうかを判断できます。

ルート・ファイル

当サイトでは、2つのルートのみを提供しています。'/page/people'はPeopleコンポーネントにルーティングされます。その他のリクエストはすべてページ・コンポーネントに送信されます。

すべてのページには、会社のロゴとリンクを含むヘッダーと、ロゴとソーシャル・メディアのアイコンを含むフッターがあります。

src/pages/Routes.jsファイルは、アプリケーションのルートを定義します。ここでは、アプリケーション、ページ参照のES6スプレッド演算子を使用しています。これは、これらのアイテムのインポートが、コンポーネントのみでなく、コンポーネントとそのfetchInitialData関数(存在する場合)を含むオブジェクトであるためです。

export default [
  {
    ...App,
    routes: [
      {
        ...People,
        path: '/page/people',
        exact: true,
        title: 'People',
      },
      {
        ...Page,
        path: '/page/:slug',
        exact: true,
        title: 'Page',
      },
    ],
  },
];

アプリケーション・コンポーネント

アプリケーション・コンポーネントは、アプリケーションのメイン・コンポーネントです。アプリケーション内のすべてのルートがヘッダーおよびフッターを取得するようにルートをラップします。

<div>
  <Header pages={data.fields.pages} headerRenditionURLs={data.headerRenditionURLs} />
  {isRoot ? (
    <Redirect to={{ pathname: `/page/${firstPageSlug}` }} />
  ) : (
    renderRoutes(route.routes)
  )}
  <Footer footerRenditionURLs={footerRenditionURLs} />
</div>

個々のルートのコンポーネントは、ページ・ディレクトリにあるページ・コンポーネントです。

src/pages/App.jsxにあるAppコンポーネントを開きます。コンポーネントはAPIをインポートして、services.jsファイルからデータを取得します。

import { fetchOceMinimalMain } from '../scripts/services';

アプリケーション・コンポーネントは、必要なデータを取得し、ヘッダー、フッターおよびページ・コンポーネントに渡します。

コンストラクタは、Webpackバンドル・ファイルで設定されたprocess.env.IS_BROWSER変数を使用して、アプリケーションがクライアントまたはサーバーで実行されているかどうかを確認します。コンポーネントがクライアントでレンダリングされている場合、データはウィンドウから取得されます。

ノート:クライアント側のルーティングを使用してページに移動すると、サーバー側のレンダリングは実行されません。かわりに、コンテンツはクライアント側のレンダリングを使用してレンダリングされます。その結果、ウィンドウにはデータが含まれず、クライアントはそのデータを取得するためにサーバー・コールを行う必要があります。

コンポーネントがサーバーにレンダリングされる場合、データはthis.props.staticContextから取得されます。つまり、Express Serverファイルから渡されるデータです。データ(デフォルト値)は、コンポーネントの状態に格納されます。

constructor(props) {
  super(props);

  let data;
  if (process.env.IS_BROWSER) {
    data = window.INITIAL_DATA;
    // Do not delete the data yet, as the Page component needs to read from it
  } else {
    const { staticContext } = this.props;
    data = staticContext.data;
  }

  this.state = {
    appData: data,
  };
}

サーバー側のレンダリング中に、サーバーからデータを取得するためにfetchInitialDataがコールされます。コール元コードであるExpress Serverコードにpromiseを返します。

function fetchInitialData() {
  return fetchOceMinimalMain();
}

コンポーネントがレンダリングされると(render()メソッドを参照)、コンポーネントの状態からすべてのデータが取得され、ヘッダー、フッター・コンポーネントおよびページ・ルートに渡されます。

src/pages/App.jsxは、fetchInitialData関数およびコンポーネントを含むオブジェクトをエクスポートします。

export default {
  fetchInitialData,
  component: App,
};

ページ・コンポーネント

ページ・コンポーネントは、ページに定義されているすべてのセクションのレンダリングを担当します。

src/pages/Page.jsxにあるPageコンポーネントを開きます。

fetchInitialDataは、サーバーからデータを取得するためにサーバー側のレンダリング中にコールされます。

function fetchInitialData() {
  const pageslug = req.path.split('/').pop();
  return fetchPage(pageslug);
}

componentDidUpdateは、ナビゲーションの変更を示す場所のパス名が変更されたかどうかを確認し、それに応じてデータをフェッチします。

componentDidUpdate() {
  const { pageSlug } = this.state;
  const { location } = this.props;
  const { pathname } = location;
  const newSlug = pathname.split('/').pop();
  if (pageSlug !== newSlug) {
    this.fetchData(newSlug);
  }
}

ender()メソッドでは、レンダリングするデータがコンポーネントの状態から取得されることがわかります。このデータにはセクションのリストがあるため、ページ・コンポーネントrender()メソッドはリストを反復処理し、リスト内の各セクションのセクション・コンポーネントをコールします。

アプリケーション・コンポーネントと同様に、ページ・コンポーネントはfetchInitialData関数およびコンポーネントを含むオブジェクトをエクスポートします。

export default {
  fetchInitialData,
  component:  Page,
};

src/components/Header.jsxにあるヘッダー・コンポーネントと、src/components/Footer.jsxにあるフッター・コンポーネントは、単にアプリケーション・コンポーネントから渡されたデータを使用します。サーバーから追加データを取得しません。

セクション・コンポーネント

src/components/Section.jsxにあるSectionコンポーネントは、ページ・コンポーネントによって使用され、MinimalSectionタイプのコンテンツ・アイテムをレンダリングするために使用されます。

このコンポーネントにはページ・コンポーネントから渡されたデータがあり、セクション・データにイメージがある場合は、サーバーからイメージのレンディションURLを取得するためのクライアント側コールが実行されます。

useEffect(() => {
  if (!image || section.RenditionURLs) return;
  getRenditionURLs(image.id).then((urls) => {
    setRenditionURLs(urls);
  }, console.error);
}, [section]);

Peopleコンポーネント

PeopleコンポーネントはPeopleページのレンダリングを担当し、src/pages/People.jsxにあります。

Oracle Content ManagementにGraphQLサポートを含める方法の詳細は、このチュートリアルを参照してください。

個人コンポーネント

src/components/Person.jsxにあるPersonコンポーネントは、Peopleコンポーネントで使用され、Personタイプのコンテンツ・アイテムをレンダリングするために使用されます。

このコンポーネントにはPeopleコンポーネントから渡されたデータがあるため、サーバーへの追加コールは必要ありません。

エラー・コンポーネント

src/components/Error.jsxにあるErrorコンポーネントは、PageおよびAppコンポーネントで使用されます。サーバーへのコール中にエラーが発生した場合は、それらがレンダリングされます。

タスク3: アプリケーションのデプロイメントの準備

React最小限サイト サイトの構築が完了したので、問題をデバッグし、アプリケーションを稼働する前にプレビューできるように、ローカル開発サーバーでそのサイトを確認する必要があります。

デプロイメント用のアプリケーションを3つのステップで準備します。

  1. Webpackを使用したアプリケーションの構築
  2. Nodeを使用したアプリケーションの実行
  3. スクリプトを使用した開発および本番でのアプリケーションの構築および実行

Webpackを使用したアプリケーションの構築

Webpackは、アプリケーションをバンドルするために使用します。サーバー上で実行されるserver-bundle.jsとクライアント上で実行されるclient-bundle.jsの2つのJavaScriptバンドルが作成されます。

React Minimumサイト・アプリケーションには、次の3つのWebpack構成ファイルがあります。

クライアント・バンドルを構築するには、クライアントWebpack構成を指定する必要があります。

webpack --config webpack.client.config.js

サーバー・バンドルを構築するには、サーバーのWebpack構成を指定する必要があります。

webpack --config webpack.server.config.js

ノードを使用したアプリケーションの実行

バンドルが作成されたら、次のコマンドを実行してサーバーを起動できます。

node server.js

スクリプトを使用した開発および本番でのアプリケーションの構築および実行

プロジェクトのルートにあるpackage.jsonファイルには、バンドルの構築とアプリケーションの実行を容易にするためのスクリプトが含まれています。

開発

開発中にdevスクリプトを使用できます。

npm run dev

このスクリプトは、クライアント・バンドルとサーバー・バンドルを構築し、ローカル・サーバーでアプリケーションを起動します。Webpackはコード変更を監視し、必要に応じてクライアント・バンドルとサーバー・バンドルを再作成します。

生産

本番環境では、ビルド・スクリプトを使用してクライアント・バンドルとサーバー・バンドルを構築します。

npm run build

スクリプトが完了したら、次のコマンドを使用してアプリケーションを実行できます。

npm run start

まとめ

このチュートリアルでは、Reactに最小限のサイトを作成しました。このサイトはGitHubにあります。このサイトでは、Oracle Content ManagementをヘッドレスCMSとして使用しています。最小限のサイト・チュートリアル用に公開されたコンテンツのチャネルを使用してOracle Content Managementを設定および構成した後、Reactサイトをインストールして実行し、必要なコンテンツをフェッチしてサイトを構築しました。

Reactの詳細は、ReactのWebサイトを参照してください。

Oracle Content Managementの重要な概念については、ドキュメンテーションを参照してください。

ReactでGraphQLを使用する場合は、このチュートリアルを確認してください。

Oracle Content ManagementのVideo PlusアセットとReactの統合方法については、このチュートリアルを参照してください。

このようなサンプルは、Oracle Content Managementのサンプル・ページのOracle Help Centerにあります。