はじめに
この記事では
- Always Free(永年無償)で利用できるOracle Content Management - Starter Edition
- Reactベースの静的サイトジェネレータであるGatsby
を利用し、Oracle Content Management(以降OCM)のアセットリポジトリで管理・公開されるアセットをGatsbyで開発したWebサイトに表示できるようにします
実現したいこと
- OCMをHeadless CMSとして利用できるように構成
- Gatsbyで作成したWebサイトに、OCMで作成・公開したアセットを表示
- Gatsby → OCMのアセット情報の取得は、GraphQLを利用
- ページ構成は、ニュース記事のアセットを新着順に一覧表示するインデックスページと、ニュース記事の詳細表示するページ、のシンプルな構成
ツール/サービスとそのバージョン
- Oracle Content Management - Starter Edition: 21.7.1
- Git: 2.30.0
- Node.js: v14.17.5
- Gatsby CLI: 3.12.0
準備
OCM - Starter Edition 環境の準備
インスタンス作成とアセット登録・公開
OCM - Starter Edition とは、Oracle Cloud Always Free(無償かつ期間の制限無し)で利用できるOCMの機能限定版です。
以下の記事を参考に、OCM - Starter Edition環境を作成します。
最終的には、以下のような形でアセット・リポジトリ内に2件のアセット(画像とコンテンツ・アイテム)が登録された状態になります
コンテンツ・アイテムは、sampleNewsType
というコンテンツ・タイプより作成されます。sampleNewsTypeは、タイトル(title)
、メイン画像(image)
、ニュース本文(body)
の3つのデータ・フィールド(属性)から構成されます。
チャネル・トークンの確認
このアセットリポジトリには、sampleChannel
という公開チャネルが設定されます。Gatsbyからアセットを参照する際に、このsampleChannel
のチャネル・トークンを利用します
チャネル・トークンは、OCMのUIからADMINISTRATION:コンテンツ
→チャネルのパブリッシュ
→sampleChannel
→右上のサイドパネルボタン
→API
より確認できます。このチャネル・トークンをメモします
Gatsby 環境の準備
Gatsbyの環境を準備します。Gatsbyの公式チュートリアルもあわせてご確認ください
事前準備
-
Node.js と git をインストールします
-
gatsby-cli
をインストールします
npm install -g gatsby-cli
Gatsbyプロジェクトの作成と起動
- Gastbyプロジェクトを作成します。ここではプロジェクト名を
my-gatsby-site
とします。また、テンプレートはデフォルトのgatsby-starter-defaultが適用されます
gatsby new my-gatsby-site
- 作成されたプロジェクトフォルダに移動し、開発サーバを起動します
cd my-gatsby-site
gatsby develop
- 以下のメッセージが表示されることを確認します
You can now view gatsby-starter-default in the browser.
⠀
http://localhost:8000/
⠀
View GraphiQL, an in-browser IDE, to explore your site's data and schema
⠀
http://localhost:8000/___graphql
OCMプラグイン
OCMプラグインは以下サイトで提供されています。
OCMプラグインのインストール
- my-gatsby-siteのプロジェクトフォルダで、以下コマンドを実行します
npm install @oracle/gatsby-source-oce
gastby-config.jsの編集
インストールされたOCMプラグイン(gatsby-source-oce)を利用するには、gastby-config.js
のプラグインリストにgatsby-source-oce
を追加する必要があります
-
エディタ等で
gastby-config.js
を開きます -
plugins:[ ]に
gatsby-source-oce
の記述を追加します。以下は追加例です
module.exports = {
siteMetadata: {
title: `Gatsby Default Starter`,
description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`,
author: `@gatsbyjs`,
siteUrl: `https://gatsbystarterdefaultsource.gatsbyjs.io/`,
},
plugins: [
`gatsby-plugin-react-helmet`,
`gatsby-plugin-image`,
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
========== (※途中省略) ==========
`gatsby-plugin-gatsby-cloud`,
// this (optional) plugin enables Progressive Web App + Offline functionality
// To learn more, visit: https://gatsby.dev/offline
// `gatsby-plugin-offline`,
{
resolve: `@oracle/gatsby-source-oce`,
options: {
name: `oce`,
contentServer: `https://snakaocmse-orasejapan.cec.ocp.oraclecloud.com`,
channelToken: `e38f35f1fece4b309350b97907c08811`,
proxyUrl: ``,
items: {
limit: 100,
query: ``,
},
renditions: `all`,
preview: false,
auth: ``,
staticAssetDownload: `true`,
staticAssetRootDir: `asset`,
},
},
],
}
[説明]構成オプションについて
構成オプションについて簡単に説明します。詳細はこちらのサイトでご確認ください
-
contentServer(必須)
- アセットを取得するOCMインスタンスのURLを指定
- 形式は
https://<インスタンス名>-<テナンシー名>.cec.ocp.oraclecloud.com
-
channelToken(必須)
- アセットを取得する公開チャネルのチャネルトークンを指定
- 準備段階でメモしたチャネルトークンを指定
-
renditions(任意)
- ビルド実行時に、デジタルアセットの自動生成されるレンディション(システムレンディション)を公開サイトのディレクトリにダウンロードするか?(しないか?)を指定
- 以下3つが指定できます
-
custom
(デフォルト): カスタムレンディションのみダウンロードする -
none
: レンディションはダウンロードしない -
all
: システムレンディション(Large/Medium/Small/Thumbnail)とカスタムレンディションを含むすべてのレンディションをダウンロードする
-
- 今回はallを指定
-
staticAssetDownload(任意)
- ビルド実行時に、デジタルアセットのバイナリファイルを公開サイトのディレクトリにダウンロードするか?(しないか?)を指定
-
true
またはfalse
(デフォルト) を指定 - 今回はtrueを指定
-
staticAssetRootDir(任意)
- デジタルアセットのダウンロード先のディレクトリを指定
-
staticAssetDownload
がtrue
の場合のみ有効 - デフォルトは
asset
- 今回はデフォルト値(asset)をそのまま利用
[説明]デジタルアセットのダウンロード設定について
今回の設定は以下のとおりです
- renditions = all
- staticAssetDownload = true
- staticAssetRootDir = asset
デジタルアセットSampleImage1.jpg
をGatsbyサイトで利用した場合、SampleImage1.jpg
は以下のように公開サイトのディレクトリにダウンロードされます
-
/asset/SampleImage1.jpg
(オリジナルファイル/原本ファイル) -
/asset/Large/SampleImage1.jpg
(Largeレンディション) -
/asset/Medium/SampleImage1.jpg
(Mediumレンディション) -
/asset/Small/SampleImage1.jpg
(Smallレンディション) -
/asset/Thumbnail/SampleImage1.jpg
(Thumbnailレンディション)
例えは、Webページ上でThumbnailレンディションを表示する場合は、<img src="/asset/Thumbnail/SampleImage1.jpg" />
と指定します
renditionsにallを設定すると、Gatsbyはオリジナルの画像とシステムレンディション(Thumbnail,Smallなど)の両方を、すべての公開済のデジタル・アセットに対して取得・生成します。これにより、ビルドプロセスに多くの処理時間とネットワーク負荷が発生する可能性があります。自動生成されるレンディションを明示的に使用する場合を除いて、noneまたはcustomオプションの使用を推奨します
確認
開発環境を起動し、レンディションがダウンロードされているか?を確認します、また、ブラウザ上でクエリを実行できるGraphiQLを使ってアセットが取得できるか?を確認します
レンディションのダウンロードを確認
- 開発環境を起動(起動中の場合はControl-Cで停止→起動)します
gatsby develop
-
my-gatsby-siteのプロジェクトの
puclic
フォルダ配下にasset
が作成されます。その中にオリジナルファイルと各レンディションファイルがダウンロードされます
-
ブラウザで
http://localhost:8000/asset/Thumbnail/SampleImage1.jpg
を開きます。サムネイルサイズの画像が表示できます
GraphiQLでOCMのアセットを取得する
-
ブラウザで
http://localhost:8000/___graphql
を開きます。左側のExplorer
にallOceAssetやoceAssetが表示されることを確認します
-
allOceAsset
をクリックすると、クエリを展開してくれます。今回はsampleNewsTypeアセットタイプのid
、name
、oceId
、slug
を取得します -
filter > oceType
を開き、eq:
を選択します -
結果が右ペインに表示されます。
edges>node>id
が自動的に追加されます。このedges>node
配下にアセットの基本情報や属性情報があります
-
edges>node
配下のid
、name
、oceId
、slug
の4項目を選択し、クエリを実行します。指定したアセット・タイプのコンテンツ・アイテムの一覧が取得できます(今回の場合、2件のコンテンツ・アイテムを取得)
-
コンテンツ・アイテムの属性情報も取得する場合は、
edges>node>oceFields
を展開します。ここではtitle
とbody
を追加で選択し、クエリと実行します。コンテンツ・アイテムの**title(タイトル)とbody(本文)**が取得できます
-
クエリで取得した情報をソートする場合は、
sort
を展開し、ソート対象のfields
とorder
を指定します。今回は、fields
に**"updatedDate"、order
に"DESC"**を指定します。実行結果は以下のとおりです
Webページの編集
GatsbyサイトのWebページで、OCMから取得したニュースコンテンツを一覧表示できるようにします
ニュース一覧の表示
GatsbyサイトのWebページにOCMから取得したsampleNewsType
のニュース・コンテンツの一覧を新着順で表示します
- my-gatsby-siteプロジェクトの
src/pages/index.js
を開き、以下の通りに編集します
//index.js
import * as React from "react"
import { graphql } from "gatsby"
import Layout from "../components/layout"
import Seo from "../components/seo"
const IndexPage = ({data}) => {
const oceposts = data.allOceAsset.nodes
return(
<Layout>
<Seo title="Home" />
<h1>ニュース一覧</h1>
{oceposts.map(post => {
console.log(post)
return (
<div key={post.id}>
<h3>{post.oceFields.title}</h3>
<img src={"/asset/Thumbnail/" + post.oceFields.image.name} alt={post.oceFields.image.name} />
</div>
)
})}
</Layout>
)
}
export const query = graphql`
{
allOceAsset(
filter: {oceType: {eq: "sampleNewsType"}}
sort: {order: DESC, fields: updatedDate}
) {
nodes {
id
oceId
name
slug
oceFields {
title
image {
name
}
}
}
}
}
`
export default IndexPage
-
index.js
を保存します -
開発環境が起動されていることを確認し、
http://localhot:8000/
を開きます。ニュース・コンテンツのtitle(タイトル)とimage(メイン画像)のサムネイルサイズの画像が表示されることを確認します
説明(index.js)
-
import { graphql } from "gatsby"
でgraphQLをインポート -
const IndexPage = ({data}) => {
のdata
に、後述のgraphqlで取得したデータが受け渡される -
graphqlの
allOceAsset()
を利用して、ニュース一覧を表示する際に必要な情報を取得-
filter: {oceType: {eq: "sampleNewsType"}}
で取得するアセット・タイプを指定 -
sort: {order: DESC, fields: updatedDate}
でアセットの更新日時順(新→旧)にソート -
oceId
、slug
はニュースの詳細ページを表示する際に利用 - ニュース画像の
image
はファイル名(image.name
)のみを取得し、ビルド時に公開環境に自動生成されるサムネイル画像をWebページ上で表示(OCMの公開アセットへの直リンクURLは利用しない)
-
ビルド
-
開発環境が起動されている場合は、Control-Cで停止します
-
Buildを実行します
gatsby build
- Buildした内容をローカル環境で確認します
gatsby serve
- 以下のメッセージが表示されるのを確認し、ブラウザで
http://localhoat:9000/
を開きます
You can now view gatsby-starter-default in the browser.
⠀
http://localhost:9000/
ニュースの詳細表示ページ
前の手順で作成したニュース一覧ページ(index.js)は、ニュース一覧を表示するだけでした。
ここでは、ニュース一覧ページでニュースタイトルや画像をクリックすると、ニュースの詳細ページが表示されるようにします
ニュース詳細ページの作成
sampleNewsType
のニュース・コンテンツを詳細表示するテンプレートを作成します
-
my-gastby-site/src/
の下にtemplates
フォルダを作成し、news-post.js
ファイルを作成します -
news-post.js
を以下の通りに編集し、保存します
// news-post.js
import * as React from "react"
import { graphql } from "gatsby"
import Layout from "../components/layout"
import Seo from "../components/seo"
const NewsPostTemplate = ({ data }) => {
const post = data.oceAsset
console.log(post)
return (
<Layout>
<Seo title={post.oceFields.title} />
<article>
<header>
<h1 itemProp="headline">{post.oceFields.title}</h1>
</header>
<img src={"/asset/" + post.oceFields.image.name} alt={post.oceFields.image.name} />
<section
dangerouslySetInnerHTML={{ __html: post.oceFields.body }}
itemProp="articleBody"
/>
</article>
<hr />
</Layout>
)
}
export default NewsPostTemplate
export const query = graphql`
query newsquery(
$id: String
){
oceAsset(oceId: {eq: $id}) {
id
slug
oceId
oceFields {
title
image {
name
}
body
}
}
}
`
説明(news-post.js)
-
graphqlで
oceAsset(oceId: {eq: $id})
の$id
はアセットを一意に識別するコンテンツIDを指定 -
属性フィールドは、
title(タイトル)
、body(本文)
、imageのname(メイン画像の名前)
を取得し、それぞれをページ上にそのまま表示します -
<img src={"/asset/" + post.oceFields.image.name} alt={post.oceFields.image.name} />
でimageのオリジナルファイルを表示します -
dangerouslySetInnerHTML={{ __html: post.oceFields.body }}
で、WYSIWYGエディタで作成した本文がそのままWebページ上に表示されます
gatsby-node.js の編集
my-gatsby-siteフォルダ配下のgatsby-node.js
を編集し、動的なページ生成を実装します。この場合は、ニュース一覧ページからリンクされるニュースの個別詳細ページを、取得したコンテンツ・アイテムの数だけ生成します
-
my-gatsby-site/gatsby-node.js
を開きます。最初は空ページですが、ここに以下のコードを入力します
//gatsby-node.js
const path = require("path");
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions;
const result = await graphql(`
query {
allOceAsset(filter: {oceType: {eq: "sampleNewsType"}}) {
nodes {
oceId
slug
id
}
}
}
`);
if (result.errors) {
throw result.errors;
}
const posts = result.data.allOceAsset.nodes;
posts.forEach((post) => {
createPage({
path: `/news/${post.slug}`,
component: path.resolve(`src/templates/news-post.js`),
context: {
id: post.oceId
},
});
});
};
-
gatsby-node.js
を保存します
説明(gatsby-node.js)
-
createPages
のAPIを利用してニュースの詳細ページを生成します。詳細はこちらの公式ドキュメントを参照 -
GraphQLでsampleNewsTypeのコンテンツ・アイテムの
oceId
、slug
、id
を取得- 詳細ページへのパス(URL)は
/news/${post.slug}
を指定 - 詳細ページのテンプレートは前の手順で作成した
./src/templates/news-post.js
を指定 - 詳細ページへの引数は
context: {id: post.oceId}
でoceId(コンテンツID)
を指定
- 詳細ページへのパス(URL)は
ニュース一覧(index.js)の編集
ニュース一覧ページ(index.js
)に詳細ページへのリンクを追加します
-
index.js
を開き、以下の通りに編集します
//index.js
import * as React from "react"
import { graphql } from "gatsby"
import { Link } from "gatsby"
import Layout from "../components/layout"
import Seo from "../components/seo"
const IndexPage = ({data}) => {
const oceposts = data.allOceAsset.nodes
return(
<Layout>
<Seo title="Home" />
<h1>ニュース一覧</h1>
{oceposts.map(post => {
console.log(post)
return (
<div key={post.id}>
<Link to={"/news/" + post.slug} itemProp="url">
<h3>{post.oceFields.title}</h3>
<img src={"/asset/Thumbnail/" + post.oceFields.image.name} alt={post.oceFields.image.name} />
</Link>
</div>
)
})}
</Layout>
)
}
export const query = graphql`
{
allOceAsset(
filter: {oceType: {eq: "sampleNewsType"}}
sort: {order: DESC, fields: updatedDate}
) {
nodes {
id
oceId
name
slug
oceFields {
title
image {
name
}
}
}
}
}
`
export default IndexPage
説明(index.js)
変更点は以下3点
- 4行目に
import { Link } from "gatsby"
を追加 - 24行目に
<Link to={"/news/" + post.slug} itemProp="url">
。リンク先はgatsby-node.jsのパスで指定した通り、/news/(コンテンツ・アイテムのslug)
を指定 - 27行目に
</Link>
を追加- Link APIはこちらの公式ドキュメントを参照
確認
- 開発環境を起動します
gatsby develop
-
http://localhost:8000/
をブラウザで開きます。以下のように各ニュースに詳細ページへのリンクが設定されます
-
ニュース(ここでは「002ニュースのタイトル」)をクリックします。ニュースの詳細ページが表示されます。また、URLも
/news/<slug>
となっていることを確認します
-
開発環境を停止します。buildし、ローカル環境で実行します
gatsby build
gatsby serve
-
http://localhost:9000/
を開き、動作を確認します
おわりに
Oracle Content Management(OCM)のアセットリポジトリで管理・公開されるアセットをGatsbyで作ったWebページに表示する流れを紹介しました。Gatsbyのコーディングは、もっとスマートな方法があると思います。改善点などあれば、お知らせいただけると幸いです
この記事を作成する際に参考にした記事を最後にリンクします(他のHeadless CMS + Gatsbyの実装サンプル方法を参考にしました)