Sitecore JSSで簡単なページを作ってみる
Tags: sitecore, jss, react
Published: 2020-01-10 17:06:45

Sitecore JSSのコードファースト開発で簡単なページを作成する方法を、チュートリアル形式で紹介します。

## 前提知識
この記事は以下の知識を前提に書いています。極力シンプルに書いているので、そこまで詳しくなくても問題ありません。

- Sitecoreの開発に関する知識
- React.jsに関する知識

## 作成するページ
`articleTitle`フィールドと`articleContent`フィールドを持つ`ArcitlePage`テンプレートのページを、`/article`に作成します。

- URL: `/article`
- Template: `ArticlePage`
    - Fields: `articleTitle`, `articleContent`

アクセスすると、`articleTitle`と`articleContent`フィールドを表示するだけのシンプルなページです。

## プロジェクトの準備
まずはSitecore JSSをインストールし、Reactのサンプルプロジェクトをセットアップしましょう。公式ドキュメントの以下のページでセットアップ方法が解説されています。

- [Quick Start | Sitecore JSS Documentation](https://jss.sitecore.com/docs/getting-started/quick-start)


またSitecore Japanの公式YouTubeチャンネルに解説動画があるので、こちらを参考にしてもOKです。

- [Sitecore JavaScript Service パッケージのインストール - YouTube](https://www.youtube.com/watch?v=bw_5MIGvKwY)
- [React サンプルアプリの作成 - YouTube](https://www.youtube.com/watch?v=uZnIS5OIMls)

## ページテンプレートを定義する
まずは`Article Page`テンプレートを定義します。  
ページテンプレートは`/sitecore/definitions/routes`フォルダに定義します。  
デフォルトではroutesフォルダは存在しないので、自分で作成しましょう。  

作成したroutesフォルダに`ArticlePage.sitecore.js`を追加します。  

```js
import {
  CommonFieldTypes,
  SitecoreIcon
} from "@sitecore-jss/sitecore-jss-manifest";

export default function (manifest) {
  manifest.addRouteType({
    name: "ArticlePage",             // テンプレート名
    displayName: "Article Page",     // テンプレートの表示名
    icon: SitecoreIcon.DocumentText, // テンプレートのアイコン
    fields: [
      {
        name: "articleTitle",                  // フィールド名
        displayName: "Article Title",          // フィールドの表示名
        type: CommonFieldTypes.SingleLineText, // フィールドタイプ
        standardValue: "$name"                 // デフォルト値
      },
      {
        name: "articleContent",
        displayName: "Article Content",
        type: CommonFieldTypes.RichText,
      }
    ]
  });
}
```

`manifest.addRouteType`関数で、ArticlePageテンプレートを定義しています。ここで定義したテンプレートは、デプロイ時にSitecore上に自動で生成されます。  
生成されるテンプレートは`App Route`テンプレートを継承しており、`pageTitle`フィールドを持っています。

## ページアイテムを定義する
次に先程作成したテンプレートで、ページアイテムを定義します。  
ページアイテムは`/data/routes`フォルダに[YAML](https://ja.wikipedia.org/wiki/YAML)形式で定義します。  

ページのURLはフォルダ構造で決まります。  
例えば`/products/camera`というURLのページを作成するには、以下のようなフォルダ構造にします。  

- routes/
    - products/
        - camera/
           - en.yml

各フォルダ直下にある`<言語名>.yml`というファイルで、そのページアイテムの定義をしています。多言語対応させたい場合は、このファイルをコピーしてファイル名を別の言語に変更しましょう。
日本語に対応するには、[Sitecore JSSでウェブサイトのデフォルト言語を日本語にする](https://dev.to/xirtardauq/sitecore-jss-506j)を参考にしてください。

今回は`/article`にページを作成するので、`routes/article/en.yml`に定義を記述します。中身は以下の例を参考にしてください。

```yaml
# アイテム名
name: article
# アイテムの表示名
displayName: Article
# テンプレート（先程定義したもの）
template: ArticlePage
# 各フィールドの値
fields:
  articleTitle: My first JSS page
  articleContent: |
    <div>
      <p>This is my first JSS page.</p>
    </div>
```

これで、`ArticlePage`テンプレートのアイテムを`/article`に作成することができました。こちらもSitecoreへのデプロイ時に対応するパスにアイテムが作成されます。

## フィールドを表示するコンポーネントを作成する
テンプレート、アイテムの作成ができたので、次はそのフィールドを表示するコンポーネントを作成します。
JSSのコンポーネントはSitecoreレンダリングとほぼ同義です。コンポーネントを作成してデプロイすると、Sitecore上にアイテム（レンダリング/データソーステンプレート）が生成されます。  
レンダリングではなく純粋なReactコンポーネントも存在しますが、今回は割愛します。  

コンポーネントを作成するには、コンソール上で`jss scaffold ArticlePageContent`を実行してください。  
以下のファイルが生成されるはずです。

- /src/components/ArticlePageContent/index.js
- /sitecore/definitions/components/ArticlePageContent.sitecore.js


1つ目はコンポーネント（レンダリング）の定義ファイルで、2つ目はそのデータソーステンプレートの定義ファイルです。

まずは`ArticlePageContent.sitecore.js`の中身を覗いてみましょう。


```js
// eslint-disable-next-line no-unused-vars
import { CommonFieldTypes, SitecoreIcon, Manifest } from '@sitecore-jss/sitecore-jss-manifest';

/**
 * Adds the ArticlePageContent component to the disconnected manifest.
 * This function is invoked by convention (*.sitecore.js) when 'jss manifest' is run.
 * @param {Manifest} manifest Manifest instance to add components to
 */
export default function(manifest) {
  manifest.addComponent({
    name: 'ArticlePageContent',
    icon: SitecoreIcon.DocumentTag,
    fields: [
      { name: 'heading', type: CommonFieldTypes.SingleLineText },
    ],
    /*
    If the component implementation uses <Placeholder> or withPlaceholder to expose a placeholder,
    register it here, or components added to that placeholder will not be returned by Sitecore:
    placeholders: ['exposed-placeholder-name']
    */
  });
}
```

基本的にはページテンプレートの定義ファイルと同じです。Sitecoreデプロイすると、この定義に基づいてレンダリングとテンプレートが生成されます。  


さて、今回はページアイテムのフィールドを表示するのでフィールドは不要です。  
デフォルトで用意されてるheadingフィールドは削除してしまいましょう。  

```js
// eslint-disable-next-line no-unused-vars
import { CommonFieldTypes, SitecoreIcon, Manifest } from '@sitecore-jss/sitecore-jss-manifest';

/**
 * Adds the ArticlePageContent component to the disconnected manifest.
 * This function is invoked by convention (*.sitecore.js) when 'jss manifest' is run.
 * @param {Manifest} manifest Manifest instance to add components to
 */
export default function(manifest) {
  manifest.addComponent({
    name: 'ArticlePageContent',
    icon: SitecoreIcon.DocumentTag,
    fields: [
-     { name: 'heading', type: CommonFieldTypes.SingleLineText },
    ],
    /*
    If the component implementation uses <Placeholder> or withPlaceholder to expose a placeholder,
    register it here, or components added to that placeholder will not be returned by Sitecore:
    placeholders: ['exposed-placeholder-name']
    */
  });
}
```

次に`/src/components/ArticlePageContent/index.js`を開いてください。  

```react
import React from 'react';
import { Text } from '@sitecore-jss/sitecore-jss-react';

const ArticlePageContent = (props) => (
  <div>
    <p>ArticlePageContent Component</p>
    <Text field={props.fields.heading} />
  </div>
);

export default HomePageContent;
```

中身はReactコンポーネントです。  
 
`props.fields`プロパティでコンポーネントのデータソースのフィールドを取得できます。  
さらに`@sitecore-jss/sitecore-jss-react`パッケージの`Text`コンポーネントを使用してフィールドをレンダリングすると、エクスペリエンスエディタでの編集が可能になります。  
`Text`の他にも`RichText`や`DateField`などが用意されているので、フィールドのタイプに応じて使い分けましょう。  

今回はコンポーネントではなくページアイテムのフィールドを取得したいのですが、デフォルトでは`props`にはそのデータが含まれていません。  
現在のページの情報を取得するには`withSitecoreContext`と呼ばれるHOCを使用する必要があります。  

```react
import React from 'react';
import {
  Text,
  withSitecoreContext  // withSitecoreContextをインポート
} from '@sitecore-jss/sitecore-jss-react';

const ArticlePageContent = (props) => (
  <div>
    <p>ArticlePageContent Component</p>
    <Text field={props.fields.heading} />
  </div>
);

// エクスポート時にwithSitecoreContextを適用する
export default withSitecoreContext()(ArticlePageContent);
```

こうすることで`props.sitecoreContext`から現在のページの情報を取得することができるようになります。このプロパティには、データベース名やページアイテムのIDなどが含まれています。
ページアイテムのフィールドを取得するには`props.sitecoreContext.route.fields`を使用します。  
最終的な`ArticlePageComponent/index.js`のソースコードは以下の通りです。  

```react
import React from 'react';
import {
  Text,
  RichText,  // RichTextコンポーネントを追加
  withSitecoreContext  // withSitecoreContextをインポート
} from '@sitecore-jss/sitecore-jss-react';

const ArticlePageContent = (props) => (
  <div>
    {/* articleTitleフィールドを表示 */}
    <h1><Text field={props.sitecoreContext.route.fields.articleTitle} /></h1>
    <div>
      {/* articleContentフィールドを表示 */}
      <RichText field={props.sitecoreContext.route.fields.articleContent} />
    </div>
  </div>
);

// withSitecoreContextを適用
export default withSitecoreContext()(ArticlePageContent);
```

## コンポーネントをページに挿入する
作成したArticlePageContentコンポーネントを、ページのプレースホルダーに挿入します。  

デフォルトで`jss-main`プレースホルダーが用意されています。`src/Layout.js`を開いてみてください。

```react
import React from 'react';
import { Placeholder, VisitorIdentification } from '@sitecore-jss/sitecore-jss-react';
import { NavLink } from 'react-router-dom';
import { withTranslation } from 'react-i18next';
import Helmet from 'react-helmet';

///////// (省略) ///////////////

const Layout = ({ route }) => (
  <React.Fragment>
    {/* react-helmet enables setting <head> contents, like title and OG meta tags */}
    <Helmet>
      <title>
        {(route.fields && route.fields.pageTitle && route.fields.pageTitle.value) || 'Page'}
      </title>
    </Helmet>

    {/*
      VisitorIdentification is necessary for Sitecore Analytics to determine if the visitor is a robot.
      If Sitecore XP (with xConnect/xDB) is used, this is required or else analytics will not be collected for the JSS app.
      For XM (CMS-only) apps, this should be removed.

      VI detection only runs once for a given analytics ID, so this is not a recurring operation once cookies are established.
    */}
    <VisitorIdentification />

    <Navigation />

    {/* root placeholder for the app, which we add components to using route data */}
    <div className="container">
      <Placeholder name="jss-main" rendering={route} />
    </div>
  </React.Fragment>
);

export default Layout;

```

このファイルは、ページ全体で使用するレイアウトの定義ファイルです。`<Placeholder name="jss-main" rendering={route}>`の部分でプレースホルダーを生成しています。  
プレースホルダを追加するには、[Sitecore JSSでレイアウトにプレースホルダを追加する](https://dev.to/xirtardauq/sitecore-jss-42m7)を参考にしてください。

この`jss-main`プレースホルダーに、先程作成したコンポーネントを挿入します。先程定義した`/data/routes/article/en.yml`ファイルを開いてください。  

```yaml
name: article
displayName: Article
template: ArticlePage
fields:
  articleTitle: My first JSS page
  articleContent: |
    <div>
      <p>This is my first JSS page.</p>
    </div>
# jss-mainプレースホルダーにTopPageContentコンポーネントを登録
placeholders:
  jss-main:
  - componentName: ArticlePageContent
```

最後の4行を追加しました。ここではプレースホルダにどのコンポーネントを挿入するかを定義します。ページアイテムのプレゼンテーション詳細を設定しているイメージです。
コンポーネントのデータソースのフィールドを設定することもできますが、今回は使用しないため割愛します。


## 動作確認
コマンドラインで`jss start`を実行して、`/article`ページにアクセスしてみましょう。  
設定したフィールドの値が表示されれば成功です。

## デプロイ
以下のページでデプロイ方法が解説されています。  

- [Server Setup | Sitecore JSS Documentation](https://jss.sitecore.com/docs/getting-started/jss-server-install)
- [App Deployment | Sitecore JSS Documentation](https://jss.sitecore.com/docs/getting-started/app-deployment)

Sitecore Japanの公式YouTubeチャンネルで日本語の解説もあるので、ぜひ参考にしてください。

- [JSS アプリを Sitecore に展開 - YouTube](https://www.youtube.com/watch?v=neQEdh8s84A)