- チュートリアル
- プレビュー
Next.jsのプレビューモードを利用して、プレビュー環境を作成する
このチュートリアルでは、Next.jsの Preview Mode と、Newtのプレビュー設定を利用して、プレビュー環境を作成する手順を紹介します。
前提条件
- Next.jsの
v9.3
以上を利用して、サイトを作成していること - 作成したサイトがデプロイ済みであること
- Next.jsの API Routes について理解していること
- NewtのJS SDKである newt-client-js の基本的な利用方法について理解していること
- newt-client-jsの
v3.1.0
以上を利用していること
概要
Next.jsのPreview Modeを利用して、プレビュー用のAPIルートを作成し、プレビューデータを取得できるようにします。
また、Newtのコンテンツ編集画面から、作成したプレビュー環境にアクセスできるようにします。
ここでは、以下の流れでプレビュー処理を行うものとして、実装を進めていきます。
- Newtの管理画面から「プレビュー」ボタンをクリックする
- プレビュー用のAPIルート
/api/preview
に、secret
とslug
のクエリパラメータをつけてアクセスする secret
とslug
の値を検証し、問題なければコンテンツ詳細ページ/article/{slug}
にリダイレクトする- コンテンツ詳細ページの
getStaticProps
でプレビューデータを取得して表示する
もしパスが異なる場合は、適宜読み替えながらチュートリアルを進めてください。
1. Newt API Tokenを作成する
はじめに、Newtの管理画面に入り、スペース設定 > APIキー のページからNewt API Tokenを作成します。
※ 下書き中のコンテンツを取得するためには、Newt APIを利用します。
名前と取得対象を決めて「作成」を押します。
2. プレビューデータの取得メソッドを作成する
プレビューデータを取得する getArticleBySlug
を実装します。引数に preview
を渡し、true
の場合は下書きを含む全コンテンツを取得、false
の場合は公開コンテンツのみを取得するようにします。
newt-client-js を利用します。
'YOUR_NEWT_API_TOKEN'
のところに1で作成したNewt API Tokenを設定します。
'YOUR_NEWT_CDN_API_TOKEN'
のところにはNewt CDN API Tokenを設定してください。
spaceUid・appUid・modelUidには、プレビューデータの取得対象の値を設定します。
// lib/api.js
import { createClient } from 'newt-client-js'
// Newt CDN APIのクライアント(公開コンテンツのみ取得)
const newtCdnClient = createClient({
spaceUid: 'YOUR_SPACE_UID',
token: 'YOUR_NEWT_CDN_API_TOKEN',
apiType: 'cdn',
})
// Newt APIのクライアント(全コンテンツ取得)
const newtApiClient = createClient({
spaceUid: 'YOUR_SPACE_UID',
token: 'YOUR_NEWT_API_TOKEN',
apiType: 'api',
})
export async function getArticleBySlug(slug, preview) {
const client = preview ? newtApiClient : newtCdnClient
const article = await client.getFirstContent({
appUid: 'YOUR_APP_UID',
modelUid: 'YOUR_MODEL_UID',
query: { slug },
})
return article
}
TypeScriptで実装する場合は、以下のようになります。
getArticleBySlug
の返り値の型として Promise<Article | null>
を指定していますが、このArticle
の型は、Newtの管理画面で設定したモデル情報をもとに定義してください。
// lib/api.ts
import { createClient } from 'newt-client-js'
// Newt CDN APIのクライアント(公開コンテンツのみ取得)
const newtCdnClient = createClient({
spaceUid: 'YOUR_SPACE_UID',
token: 'YOUR_NEWT_CDN_API_TOKEN',
apiType: 'cdn',
})
// Newt APIのクライアント(全コンテンツ取得)
const newtApiClient = createClient({
spaceUid: 'YOUR_SPACE_UID',
token: 'YOUR_NEWT_API_TOKEN',
apiType: 'api',
})
export async function getArticleBySlug(
slug: string,
preview: boolean
): Promise<Article | null> {
const client = preview ? newtApiClient : newtCdnClient
const article = await client.getFirstContent<Article>({
appUid: 'YOUR_APP_UID',
modelUid: 'YOUR_MODEL_UID',
query: { slug },
})
return article
}
3. プレビュー用のAPIルートを作成する
プレビュー用のAPIルートを作成します。ここではエンドポイントが /api/preview
となるように、pages/api/preview.js
というファイルを用意します。この処理では、以下のことを行います。
- リクエストが有効なものか、クエリパラメータのsecretの値で検証する(ここでは
PREVIEW_SECRET
という環境変数を利用する) - slugと対応するコンテンツがあるか検証する
- Cookieを設定し、プレビューモードを有効にする
- 取得した情報からパスを指定してリダイレクトする
// pages/api/preview.js
import { getArticleBySlug } from '../../lib/api'
export default async (req, res) => {
// secretを検証する、slugパラメータの有無を検証する
if (req.query.secret !== process.env.PREVIEW_SECRET || !req.query.slug) {
return res.status(401).json({ message: 'Invalid token' })
}
// slugと対応するコンテンツがあるか検証する
const article = await getArticleBySlug(req.query.slug, true)
if (!article) {
return res.status(401).json({ message: 'Invalid slug' })
}
// Cookieを設定し、プレビューモードを有効にする
res.setPreviewData({})
// 取得した情報からパスを指定してリダイレクトする
res.redirect(`/article/${article.slug}`)
}
TypeScriptで実装する場合は、以下のようになります。
// pages/api/preview.ts
import type { NextApiRequest, NextApiResponse } from 'next'
import { getArticleBySlug } from '../../lib/api'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
// secretを検証する、slugパラメータの有無を検証する
if (req.query.secret !== process.env.PREVIEW_SECRET || !req.query.slug) {
return res.status(401).json({ message: 'Invalid token' })
}
// slugと対応するコンテンツがあるか検証する
const article = await getArticleBySlug(req.query.slug + '', true)
if (!article) {
return res.status(401).json({ message: 'Invalid slug' })
}
// Cookieを設定し、プレビューモードを有効にする
res.setPreviewData({})
// 取得した情報からパスを指定してリダイレクトする
res.redirect(`/article/${article.slug}`)
}
4. getStaticPropsを更新する
次に、コンテンツ詳細ページの getStaticProps
を更新します。
プレビューモードのCookieが設定されている場合、getStaticProps
がビルド時ではなく、リクエスト時に呼び出されます。
また、引数として渡される context
オブジェクトの context.preview
の値が true
となります。
2で作成した getArticleBySlug
を利用して、以下のように実装します。
// pages/article/[slug].js
export async function getStaticProps(context) {
const { params, preview } = context
const article = await getArticleBySlug(params.slug, preview)
return {
props: {
article,
},
}
}
TypeScriptで実装する場合は、以下のようになります。
// pages/article/[slug].tsx
type Context = {
params: {
slug: string
}
preview?: boolean
}
export async function getStaticProps(context: Context) {
const { params, preview = false } = context
const article = await getArticleBySlug(params.slug, preview)
return {
props: {
article,
},
}
}
これでNext.jsの設定は終了です。変更をコミットして、デプロイしておきましょう。
5. プレビュー設定を行う
最後に、Newtの管理画面に入り、プレビュー設定を行います。
モデル設定の右上から「プレビュー設定」に進みます。
プレビュー用のAPIルート /api/preview
に secret
と slug
のクエリパラメータをつけてアクセスするよう、プレビューURLを指定します。
サイトのドメインが https://nextjs-preview.newt.so
、secretが hogehoge
の場合、プレビューURLは以下のように指定します。
https://nextjs-preview.newt.so/api/preview?secret=hogehoge&slug={slug}
モデルが slug
というフィールドを持つ場合、{slug}
のように記載することで、各コンテンツのslugの値がプレビューURLに展開されます。
以上ですべての設定ができました。
コンテンツ編集画面からプレビューが見れるか確認しましょう。
もし、プレビューが見れない場合は、プレビューURLが正しく指定されているか、tokenやsecretの値が正しいか確認してみてください。
また、Next.jsのプレビュー機能について、より詳しく確認したい方は、Vercelの Preview Mode をご確認ください。