NewtとGatsbyを利用してブログを作成する

このチュートリアルでは、Newtと Gatsby を利用して、ブログを作成する手順を紹介します。
具体的には、Newtで管理しているコンテンツの一覧ページと詳細ページを作る手順を紹介します。

記事内で使用している主なソフトウェアのバージョン

  • Gatsby(gatsby): 5.4.2
  • gatsby-source-newt(gatsby-source-newt): 2.0.7

概要

Gatsbyでサイトを作成し、Newtのコンテンツ情報を取得できるようにします。
コンテンツの一覧ページ(パス: /)と詳細ページ(パス: /articles/:slug 。slugがarticle-1の場合は /articles/article-1)を作成し、ローカル環境で表示を行うまでを説明します。
また、ここではビルド時にHTMLを生成する、静的サイト生成(Static Site Generation)の方法を紹介します。

1. Gatsbyのセットアップ

1-1. Node.jsの準備

Gatsby v5でサポートされるNode.jsの最低バージョンは18となります。17以前のバージョンを利用している場合は、あらかじめ18以上のバージョンをインストールしておきましょう。
アップグレードの方法は、Gatsbyの Upgrading Your Node.js Version のドキュメント等を参考にしてください。
すでに18以上のNode.jsを利用している場合は、特に作業は必要ありません。

1-2. サイトの作成

Gatsbyのセットアップを行います。create-gatsby を利用することで、簡単にGatsbyのサイトを作成できます。以下のコマンドを入力します。

npm init gatsby

コマンドを入力すると、以下の質問を聞かれるので、お好きな設定を選びましょう。

  • サイト名(ここでは gatsby-blog としました)
  • サイトを作成するフォルダ名
  • JavaScriptを利用するか、TypeScriptを利用するか(ここでは TypeScript を選択)
  • CMSを利用するか(ここでは No を選択)
  • スタイリングシステムを利用するか(ここでは No を選択)
  • 他のプラグインをインストールするか(ここでは何も選ばずに Done を選択)

質問に答えると、以下のように表示されます。

$ npm init gatsby
create-gatsby version 3.4.0

Welcome to Gatsby!

This command will generate a new Gatsby site for you in /Users/hoge/fuga with the setup you select. Let's answer some questions:

What would you like to call your site?
✔ · gatsby-blog
What would you like to name the folder where your site will be created?
✔ fuga/ gatsby-blog
✔ Will you be using JavaScript or TypeScript?
· TypeScript
✔ Will you be using a CMS?
· No (or I'll add it later)
✔ Would you like to install a styling system?
· No (or I'll add it later)
✔ Would you like to install additional features with other plugins?No items were selected

Thanks! Here's what we'll now do:

    🛠  Create a new Gatsby site in the folder gatsby-blog

✔ Shall we do this? (Y/n) · Yes
✔ Created site from template
✔ Installed Gatsby
✔ Installed plugins
✔ Created site in gatsby-blog
🎉  Your new Gatsby site  has been successfully created
at /Users/hoge/fuga/gatsby-blog.

作成したプロジェクトに移動して、開発サーバーを立ち上げます。

$ cd gatsby-blog
$ npm run develop

http://localhost:8000/ にアクセスして、以下のような画面が表示されることを確認します。

gatsby-blog1.png

1-3. パッケージマネージャーの設定(yarnを利用する場合)

yarnをパッケージマネージャーとして利用する場合、Gatsby CLIの設定ファイルを書き換える必要があります。
※ npmをパッケージマネージャーとして使う場合、1-3のステップを飛ばして構いません。

~/.config/gatsby/config.json/Users/{ユーザー名}/.config/gatsby/config.json)を以下のように修正して、packageManageryarn を指定します。
詳細は、Gatsbyの Yarn のドキュメントをご確認ください。

{
  "cli": {
    "packageManager": "yarn"
  }
}

package-lock.json を削除した後、yarn install を実行して、yarn.lock ファイルが作成されることを確認します。
これで yarn develop で開発サーバーを立ち上げられるようになりました。

2. Newtのセットアップ

次にNewtにコンテンツとAPIトークンを用意し、コンテンツの取得を行うための準備を行います。

2-1. Appを追加する

「Appを追加」をクリックして「テンプレートから追加」を選択します。

Appを追加する

表示されるテンプレートの中から「Blog」を選択して、「このテンプレートを追加」をクリックします。
Appテンプレート

テンプレートが追加されると、「投稿データ」「カテゴリデータ」「著者データ」が追加されます。

quick-start03.jpg

2-2. スペースUID・App UID・モデルUIDを確認する

スペースUIDは「スペース設定」から確認できます。

quick-start0402.jpgquick-start0503.jpg

上記の例だと、スペースUIDは sample-for-docs となります。
この値は3-1で環境変数として定義します。

また「Blog」テンプレートを追加した場合、App UIDは blog、「投稿データ」モデルUIDは article となります。
これらの値は、3-3でプラグインを追加する際に利用します。

2-3. Newt CDN API Tokenを作成する

続いて、APIリクエストに必要なトークンを発行します。
スペース設定 > APIキー のページからNewt CDN API Tokenを作成します。

quick-start06.jpg

名前と取得対象を決めて「作成」を押します。

quick-start07.jpg

ここで作成したトークンの値は3-1で環境変数として定義します。

3. Newtプラグインの追加

Newtの Gatsbyプラグイン を利用することで、Newtのコンテンツデータをより簡単に取得できます。
ここではプラグインを追加し、GraphiQLを利用してデータが取得されていることを確認します。

3-1. 環境変数の設定

Gatsbyには環境変数のビルトインサポートがあります。
開発環境用に .env.development ファイルを作成し、2-2で確認したスペースUID、2-3で作成したトークンの値を定義します。以下を、実際の値で置き換えて定義してください。

NEWT_SPACE_UID=sample-for-docs
NEWT_CDN_API_TOKEN==xxxxxxxxxxxxxxx

次に gatsby-config.ts に以下を追加します。
これで開発環境の場合は .env.development を、本番環境の場合は .env.production を参照します。

require('dotenv').config({
  path: `.env.${process.env.NODE_ENV}`,
})

続いて、.gitignore.env.* を追加します。
これで環境変数がGitにコミットされないようになりました。

node_modules/
.cache/
public
src/gatsby-types.d.ts
+ .env.*

Gatsbyの環境変数について、詳細はGatsbyの Environment Variables のドキュメントをご確認ください。

3-2. gatsby-source-newtのインストール

次に gatsby-source-newt をインストールします。

npm install gatsby-source-newt
# or
yarn add gatsby-source-newt

3-3. プラグインの追加

Newtのソースプラグインを追加して、Newtで定義した投稿データを取得します。

gatsby-config.tspluginsgatsby-source-newt の記述を追加します。
プラグイン追加の詳細についてはGatsbyの Add a Plugin to Your Site のドキュメントをご確認ください。

// gatsby-config.ts

import type { GatsbyConfig } from 'gatsby'

require('dotenv').config({
  path: `.env.${process.env.NODE_ENV}`,
})

const config: GatsbyConfig = {
  siteMetadata: {
    title: `gatsby-blog`,
    siteUrl: `https://www.yourdomain.tld`,
  },
  // More easily incorporate content into your pages through automatic TypeScript type generation and better GraphQL IntelliSense.
  // If you use VSCode you can also use the GraphQL plugin
  // Learn more at: https://gatsby.dev/graphql-typegen
  graphqlTypegen: true,
- plugins: [],
+ plugins: [
+   {
+     resolve: 'gatsby-source-newt',
+     options: {
+       spaceUid: process.env.NEWT_SPACE_UID,
+       token: process.env.NEWT_CDN_API_TOKEN,
+       appUid: 'blog',
+       models: [
+         {
+           uid: 'article',
+         },
+       ],
+     },
+   },
+ ],
}

export default config

上記の指定を行うと、Newtから取得した投稿データは newtArticleallNewtArticle というタイプでアクセスできるようになります。

このタイプは uid から決定されるため、例えば uidauthor の場合は newtAuthorallNewtAuthor となります。

models: [
  {
    uid: 'author',
  },
],

uidから決定するのではなく、自身で定義したい場合は、type パラメータを指定してください。例えば typepost の場合は newtPostallNewtPost となります。

models: [
  {
    uid: 'article',
    type: 'post',
  },
],

それでは、開発サーバーを再度立ち上げて、http://localhost:8000/___graphql にアクセスして、GraphiQL を開いてみましょう。

以下のようにクエリを入力・実行して、データが返却されることを確認します。

query MyQuery {
  allNewtArticle {
    edges {
      node {
        _id
        title
        slug
      }
    }
  }
}

gatsby-blog2.png

4. 一覧ページの作成

4-1. 言語の設定をする

gatsby-ssr.tsx を作成し、lang 属性を設定します。ここでは日本語 ja を指定します。
gatsby-ssr.tsx の詳細については、Gatsbyの Gatsby Server Rendering APIs をご確認ください。

exports.onRenderBody = ({ setHtmlAttributes }) => {
  setHtmlAttributes({ lang: 'ja' })
}

4-2. 投稿一覧を取得する

Gatsbyでは src/pages ディレクトリの配下にファイルを作成すると、自動的にルートとして利用できるようになります。
例えば、以下のようにルーティングされます。

  • src/pages/blog/index.tsx/blog
  • src/pages/blog/first-post.tsx/blog/first-post

※ ルーティングの詳細については、Gatsbyの Routing のドキュメントをご確認ください。

ここではトップページ(パス: /)で投稿一覧を表示したいので、src/pages/index.tsx ファイルを修正します。
まず、以下の query を追加しましょう。

// src/pages/index.tsx

import { graphql } from 'gatsby'

// (中略)

export const query = graphql`
  query IndexPage {
    allNewtArticle {
      edges {
        node {
          _id
          title
          slug
        }
      }
    }
  }
`

Gatsbyでは graphql タグを使用することで、ページコンポーネントがデータを利用できます。ここでは、投稿一覧の表示で利用する _idtitleslug 情報を取得しています。
また、オペレーション名IndexPage と指定しています。

ページ内でのデータの取得について、詳細はGatsbyの Querying Data in Pages with GraphQL のドキュメントをご確認ください。

4-3. 投稿一覧を表示する

次に、取得した投稿一覧を表示します。
src/pages/index.tsx は以下のようになります。

// src/pages/index.tsx

import * as React from 'react'
import { graphql, Link } from 'gatsby'
import type { HeadFC, PageProps } from 'gatsby'

const IndexPage = ({ data }: PageProps<Queries.IndexPageQuery>) => {
  return (
    <main>
      <ul>
        {data.allNewtArticle.edges.map((edge) => (
          <li key={edge.node._id}>
            <Link to={`/articles/${edge.node.slug}`}>{edge.node.title}</Link>
          </li>
        ))}
      </ul>
    </main>
  )
}

export default IndexPage

export const Head: HeadFC = () => (
  <>
    <title>Newt・Gatsbyブログ</title>
    <meta name="description" content="NewtとGatsbyを利用したブログです" />
  </>
)

export const query = graphql`
  query IndexPage {
    allNewtArticle {
      edges {
        node {
          _id
          title
          slug
        }
      }
    }
  }
`

4-2で作成した query の結果は data という引数から利用できます。
型として指定されている PageProps<Queries.IndexPageQuery> ですが、PagePropsQueries.IndexPageQuery というジェネリクスを渡すことで、query の実行結果の型を指定してます。
この Queries.IndexPageQuery ですが、Gatsbyの GraphQL Typegen によって自動で生成される型となります。オペレーション名を IndexPage としなかった場合は、適切な名称に置き換えてください。
また、Gatsby Head API を利用して、タイトルとディスクリプションを設定しています。

http://localhost:8000/ にアクセスして、以下のように投稿一覧が表示されれば成功です。

gatsby-blog3.png

5. 詳細ページの作成

5-1. 投稿詳細を取得する

Gatsbyでは {Product.name} のようにページ名に波括弧を使うことで動的なルーティングを作成できます。例えば、以下のようにルーティングされます。

  • src/pages/products/{Product.name}.tsx/products/burger

ここでは、/articles/:slug/articles/article-1 など)のパスで投稿の詳細を表示したいので、src/pages/articles/{NewtArticle.slug}.tsx のファイルを作成します。

この場合、各コンテンツのslug情報が props.params.slug として利用できます。また、slugと対応する各nodeのid情報(各コンテンツの _id ではないのでご注意ください)が props.pageContext.id として利用できます。
※ 詳細についてはGatsbyの File System Route API のドキュメントをご確認ください。

src/pages/articles/{NewtArticle.slug}.tsx に、以下の query を追加します。

// src/pages/articles/{NewtArticle.slug}.tsx

import { graphql } from 'gatsby'

export const query = graphql`
  query ArticlePage($id: String) {
    newtArticle(id: { eq: $id }) {
      title
      body
    }
  }
`

このクエリは pageContextid を利用して、スラッグに該当する1件の投稿データを取得しています。
ここでは、投稿詳細の表示で利用する titlebody 情報を取得しています。

5-2. 投稿詳細を表示する

最後に、取得した投稿詳細を表示します。
src/pages/articles/{NewtArticle.slug}.tsx は以下のようになります。

// src/pages/articles/{NewtArticle.slug}.tsx

import * as React from 'react'
import { graphql } from 'gatsby'
import type { HeadFC, PageProps } from 'gatsby'

const ArticlePage = ({ data }: PageProps<Queries.ArticlePageQuery>) => {
  return (
    <main>
      <h2>{data.newtArticle?.title}</h2>
      <div dangerouslySetInnerHTML={{ __html: data.newtArticle?.body + '' }} />
    </main>
  )
}

export default ArticlePage

export const Head: HeadFC<Queries.ArticlePageQuery> = ({ data }) => (
  <>
    <title>{data.newtArticle?.title}</title>
    <meta name="description" content="投稿詳細ページです" />
  </>
)

export const query = graphql`
  query ArticlePage($id: String) {
    newtArticle(id: { eq: $id }) {
      title
      body
    }
  }
`

4-3と同様に、Gatsbyの GraphQL Typegen によって自動で生成される Queries.ArticlePageQuery を利用します。オペレーション名を ArticlePage としなかった場合は、適切な名称に置き換えてください。

※ bodyの表示で利用されている dangerouslySetInnerHTML はXSSの危険性があるため、利用には注意が必要です。ここでは、Newtで管理している投稿情報を表示するものであり、不特定多数のユーザーが入力できるものを表示するわけではないため、安全なものとして利用しています。

これで、投稿詳細についての設定も完了です。
http://localhost:8000/articles/article-3/ にアクセスして、以下のように投稿詳細が表示されれば成功です。

gatsby-blog4.png

次のステップ

このチュートリアルを行うことで、Gatsbyのサイトを作成し、開発環境でコンテンツの取得・表示を行う方法を学習しました。
更に深く学習したい方は、以下のチュートリアルもおすすめです。

ホスティングを行いたい方

その他にも様々なチュートリアルを用意しているので、ぜひ チュートリアル のページもご確認ください。

Newt Made in Newt