- チュートリアル
- フレームワーク
NewtとNext.jsを利用してブログを作成する
このチュートリアルでは、Newtと Next.js を利用して、ブログを作成する手順を紹介します。
具体的には、Newtで管理しているコンテンツの一覧ページと詳細ページを作る手順を紹介します。
記事内で使用している主なソフトウェアのバージョン
- Next.js(
next
): 13.3.0 - newt-client-js(
newt-client-js
): 3.2.4
概要
Next.jsでプロジェクトを作成し、Newtのコンテンツ情報を取得できるようにします。
コンテンツの一覧ページ(パス: /
)と詳細ページ(パス: /articles/:slug
。slugがarticle-1の場合は /articles/article-1
)を作成し、ローカル環境で表示を行うまでを説明します。
また、ここではビルド時にHTMLを生成する、静的生成(Static Generation)の方法を紹介します。
1. Next.jsのセットアップ
はじめに、Next.jsのセットアップを行います。Create Next App を利用することで、簡単にNext.jsのプロジェクトを作成できます。
以下のどちらかのコマンドを入力します。
npx create-next-app@latest
# or
yarn create next-app
コマンドを入力すると、以下の質問を聞かれるので、お好きな設定を選びましょう。
- プロジェクト名(ここでは
nextjs-blog
としました) - TypeScriptを利用するか(ここでは
Yes
を選択) - ESLintを利用するか(ここでは
Yes
を選択) - Tailwind CSSを利用するか(ここでは
No
を選択) - src/ ディレクトリを使用するか(ここでは
No
を選択) - app/ ディレクトリを使用するか(ここでは
No
を選択) - インポートエイリアスの設定をどうするか(ここでは
@/*
を選択)
yarnを利用した場合、以下のように表示されます。
$ yarn create next-app
yarn create v1.22.19
[1/4] 🔍 Resolving packages...
[2/4] 🚚 Fetching packages...
[3/4] 🔗 Linking dependencies...
[4/4] 🔨 Building fresh packages...
success Installed "create-next-app@13.3.0" with binaries:
- create-next-app
✔ What is your project named? … nextjs-blog
✔ Would you like to use TypeScript with this project? … Yes
✔ Would you like to use ESLint with this project? … Yes
✔ Would you like to use Tailwind CSS with this project? … No
✔ Would you like to use `src/` directory with this project? … No
✔ Would you like to use experimental `app/` directory with this project? … No
✔ What import alias would you like configured? … @/*
Creating a new Next.js app in /Users/hoge/fuga/nextjs-blog.
作成したプロジェクトに移動して、開発サーバーを立ち上げます。
$ cd nextjs-blog
$ yarn dev
http://localhost:3000
にアクセスして、以下のような画面が表示されることを確認します。
2. Newtのセットアップ
次にNewtにコンテンツとAPIトークンを用意し、コンテンツの取得を行うための準備を行います。
2-1. Appを追加する
「Appを追加」をクリックして「テンプレートから追加」を選択します。
表示されるテンプレートの中から「Blog」を選択して、「このテンプレートを追加」をクリックします。
テンプレートが追加されると、「投稿データ」「カテゴリデータ」「著者データ」が追加されます。
2-2. スペースUID・App UID・モデルUIDを確認する
スペースUIDは「スペース設定」から確認できます。
上記の例だと、スペースUIDは sample-for-docs
となります。
この値は3-1で環境変数として定義します。
また「Blog」テンプレートを追加した場合、App UIDは blog
、「投稿データ」モデルUIDは article
となります。
これらの値は、4-3や5-1で投稿情報を取得する際に利用します。
2-3. Newt CDN API Tokenを作成する
続いて、APIリクエストに必要なトークンを発行します。
スペース設定 > APIキー のページからNewt CDN API Tokenを作成します。
名前と取得対象を決めて「作成」を押します。
ここで作成したトークンの値は3-1で環境変数として定義します。
3. リクエストの準備
Newtの SDK を利用することで、NewtのAPIをより簡単に利用できます。
ここではSDKを利用して、NewtのAPIクライアントを作成します。
3-1. 環境変数の設定
Next.jsには環境変数のビルトインサポートがあり、.env.local
を使用して、環境変数をロードできます。Next.jsの環境変数について、詳細は Environment Variables のドキュメントをご確認ください。
ここでは、.env.local
ファイルを作成し、2-2で確認したスペースUID、2-3で作成したトークンの値を定義します。以下を、実際の値で置き換えて定義してください。
NEWT_SPACE_UID=sample-for-docs
NEWT_CDN_API_TOKEN=xxxxxxxxxxxxxxx
上記のように定義しておくと、process.env.NEWT_SPACE_UID
や process.env.NEWT_CDN_API_TOKEN
として利用できるようになります。
3-2. newt-client-jsのインストール
次に newt-client-js をインストールします。
npm install newt-client-js
# or
yarn add newt-client-js
3-3. APIクライアントの作成
CDN APIを利用するためのクライアントを作成します。
spaceUid
と token
のところには3-1で設定した環境変数を入力します。
ここではCDN APIを利用するので、apiType
には cdn
を指定しましょう。
// lib/newt.ts
import { createClient } from 'newt-client-js'
const client = createClient({
spaceUid: process.env.NEWT_SPACE_UID + '',
token: process.env.NEWT_CDN_API_TOKEN + '',
apiType: 'cdn',
})
これで、NewtにAPIリクエストを送るための準備ができました。
4. 一覧ページの作成
4-1. 言語の設定をする
pages/_document.tsx
にある lang 属性を修正します。ここでは日本語 ja
を指定します。
import { Html, Head, Main, NextScript } from 'next/document'
export default function Document() {
return (
- <Html lang="en">
+ <Html lang="ja">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
4-2. 投稿の型を定義する
投稿の型 Article
を定義します。
このチュートリアルでは、_id
・title
・slug
・body
のみを使うため、以下のように定義しておきます。
// types/article.ts
export interface Article {
_id: string
title: string
slug: string
body: string
}
4-3. 投稿一覧の取得メソッドを作成する
投稿一覧を取得するために、lib/newt.ts
のファイルに getArticles
メソッドを追加します。
SDKが提供している getContents メソッドはNewtのコンテンツ一覧を取得するためのメソッドです。getContentsのパラメータに Article
の型を渡すことで、返却される items
の型として Article[]
が指定されます。
また、selectパラメータを利用して、取得するフィールドを _id
・title
・slug
・body
のみに制限します。
import { createClient } from 'newt-client-js'
+ import type { Article } from '@/types/article'
const client = createClient({
spaceUid: process.env.NEWT_SPACE_UID + '',
token: process.env.NEWT_CDN_API_TOKEN + '',
apiType: 'cdn',
})
+ export const getArticles = async () => {
+ const { items } = await client.getContents<Article>({
+ appUid: 'blog',
+ modelUid: 'article',
+ query: {
+ select: ['_id', 'title', 'slug', 'body'],
+ },
+ })
+ return items
+ }
1でインポートエイリアスに @/*
を指定したので、Article
のパスに @/types/article
と指定しています。
4-4. 投稿一覧を表示する
Next.jsではファイルシステムベースのルーティングを採用しており、pages
ディレクトリの配下にファイルを作成すると、自動的にルートとして利用できるようになります。
例えば、以下のようにルーティングされます。
pages/blog/index.ts
→/blog
pages/blog/first-post.ts
→/blog/first-post
※ ルーティングの詳細については、Next.jsの Routing のドキュメントをご確認ください。
ここではトップページ(パス: /
)で投稿一覧を表示したいので、pages/index.tsx
のファイルを修正します。
4-3で作成した getArticles
を利用して、以下のように書き換えます。
// pages/index.tsx
import Head from 'next/head'
import Link from 'next/link'
import styles from '@/styles/Home.module.css'
import { getArticles } from '@/lib/newt'
import type { Article } from '@/types/article'
export default function Home({ articles }: { articles: Article[] }) {
return (
<>
<Head>
<title>Newt・Next.jsブログ</title>
<meta name="description" content="NewtとNext.jsを利用したブログです" />
</Head>
<main className={styles.main}>
<ul>
{articles.map((article) => {
return (
<li key={article._id}>
<Link href={`articles/${article.slug}`}>{article.title}</Link>
</li>
)
})}
</ul>
</main>
</>
)
}
export const getStaticProps = async () => {
const articles = await getArticles()
return {
props: {
articles,
},
}
}
ここでは getStaticProps という関数をエクスポートしています。これにより、Next.jsはビルド時に getStaticProps
から返されるpropsを使って事前レンダリングを行います。静的生成でサイトを作成する場合は、この関数を使います。
今回の場合は、propsとして articles
を渡し、一覧ページで全投稿のタイトルを表示するようにしています。
http://localhost:3000/
にアクセスして、以下のように投稿一覧が表示されれば成功です。
5. 詳細ページの作成
5-1. 投稿詳細の取得メソッドを作成する
投稿詳細を取得するために、lib/newt.ts
のファイルに getArticleBySlug
メソッドを追加します。
SDKが提供している getFirstContent メソッドはクエリに該当するコンテンツのうち、最初の1件を返却するメソッドです。指定したスラッグのコンテンツを取得したい場合は、このメソッドを利用します。
import { createClient } from 'newt-client-js'
import type { Article } from '@/types/article'
const client = createClient({
spaceUid: process.env.NEWT_SPACE_UID + '',
token: process.env.NEWT_CDN_API_TOKEN + '',
apiType: 'cdn',
})
export const getArticles = async () => {
const { items } = await client.getContents<Article>({
appUid: 'blog',
modelUid: 'article',
query: {
select: ['_id', 'title', 'slug', 'body'],
},
})
return items
}
+ export const getArticleBySlug = async (slug: string) => {
+ const article = await client.getFirstContent<Article>({
+ appUid: 'blog',
+ modelUid: 'article',
+ query: {
+ slug,
+ select: ['_id', 'title', 'slug', 'body'],
+ },
+ })
+ return article
+ }
5-2. 投稿詳細を表示する
Next.jsでは [param]
のようにしてページ名に角括弧を使うことで動的なルーティング(Dynamic Routes)を作成できます。ここでは、/articles/:slug
(/articles/article-1
など)のパスで投稿の詳細を表示したいので、pages/articles/[slug].tsx
のファイルを作成します。
5-1で作成した getArticleBySlug
を利用して、以下のように記載します。
// pages/articles/[slug].tsx
import Head from 'next/head'
import styles from '@/styles/Home.module.css'
import { getArticles, getArticleBySlug } from '@/lib/newt'
import type { Article } from '@/types/article'
export default function Article({ article }: { article: Article }) {
return (
<>
<Head>
<title>{article.title}</title>
<meta name="description" content="投稿詳細ページです" />
</Head>
<main className={styles.main}>
<h1>{article.title}</h1>
<div dangerouslySetInnerHTML={{ __html: article.body }} />
</main>
</>
)
}
export const getStaticPaths = async () => {
const articles = await getArticles()
return {
paths: articles.map((article) => ({
params: {
slug: article.slug,
},
})),
fallback: false,
}
}
export const getStaticProps = async ({
params,
}: {
params: { slug: string }
}) => {
const { slug } = params
const article = await getArticleBySlug(slug)
return {
props: {
article,
},
}
}
ここでは投稿一覧のページでも利用した getStaticProps
に加えて、getStaticPaths の関数をエクスポートしています。getStaticPaths
はNext.jsで動的なルーティングを使う場合に利用する関数で、静的に生成するパスのリストを定義しておきます。
今回の場合は、全投稿のスラッグを定義しておきます。
また、fallback
のパラメータで、getStaticPathsで定義していないパスでアクセスされた場合の挙動を設定します。ここでは、定義されていないパスでアクセスされた場合は、404ページを返すものとし、false
を設定しています。fallbackパラメータについての詳細は、Next.jsの getStaticPaths のドキュメントをご確認ください。
※ bodyの表示で利用されている dangerouslySetInnerHTML はXSSの危険性があるため、利用には注意が必要です。ここでは、Newtで管理している投稿情報を表示するものであり、不特定多数のユーザーが入力できるものを表示するわけではないため、安全なものとして利用しています。
これで、投稿詳細についての設定も完了です。
http://localhost:3000/articles/article-3
にアクセスして、以下のように投稿詳細が表示されれば成功です。
次のステップ
このチュートリアルを行うことで、Next.jsのプロジェクトを作成し、開発環境でコンテンツの取得・表示を行う方法を学習しました。
更に深く学習したい方は、以下のチュートリアルもおすすめです。
Vercelと接続してホスティングを行いたい方
→ GitHubのリポジトリとVercelを接続して、ホスティングする
プレビュー環境を作成したい方
→ Next.jsのプレビューモードを利用して、プレビュー環境を作成する
問い合わせフォームを作成したい方
→ NewtとNext.jsを利用して、問い合わせフォームを作成する
その他にも様々なチュートリアルを用意しているので、ぜひ チュートリアル のページもご確認ください。