Next.jsアプリケーションの静的エクスポートを作成する方法
Next.jsは静的サイトまたはシングルページアプリケーション(SPA)として開始し、その後、サーバーが必要な機能を使用するようにアップグレードすることができます。
next buildを実行すると、Next.jsはルートごとにHTMLファイルを生成します。厳密なSPAを個別のHTMLファイルに分割することで、Next.jsはクライアント側での不要なJavaScriptコードの読み込みを避け、バンドルサイズを削減し、ページの読み込みをより高速化できます。
Next.jsはこの静的エクスポートをサポートしているため、HTML/CSS/JS静的アセットを配信できる任意のウェブサーバーにデプロイおよびホストできます。
設定
静的エクスポートを有効にするには、next.config.js内の出力モードを変更します。
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
output: 'export',
// オプション:リンク`/me` -> `/me/`に変更し、`/me.html` -> `/me/index.html`を発行
// trailingSlash: true,
// オプション:自動的な`/me` -> `/me/`を防止し、代わりに`href`を保持
// skipTrailingSlashRedirect: true,
// オプション:出力ディレクトリを`out` -> `dist`に変更
// distDir: 'dist',
}
module.exports = nextConfignext buildを実行した後、Next.jsはアプリケーションのHTML/CSS/JSアセットを含むoutフォルダを作成します。
サポートされている機能
Next.jsのコアは静的エクスポートをサポートするように設計されています。
Server Components
next buildを実行して静的エクスポートを生成すると、appディレクトリ内で消費されるServer Componentsはビルド中に実行され、従来の静的サイト生成に似ています。
結果のコンポーネントは、初期ページロード用に静的HTMLにレンダリングされ、ルート間のクライアントナビゲーション用に静的ペイロードになります。静的エクスポートを使用する場合、動的サーバー関数を消費しない限り、Server Componentsに変更は必要ありません。
export default async function Page() {
// このフェッチは`next build`中にサーバー上で実行されます
const res = await fetch('https://api.example.com/...')
const data = await res.json()
return <main>...</main>
}Client Components
クライアント上でデータフェッチングを実行する場合は、SWRを使用したClient Componentを使用してリクエストをメモ化できます。
'use client'
import useSWR from 'swr'
const fetcher = (url: string) => fetch(url).then((r) => r.json())
export default function Page() {
const { data, error } = useSWR(
`https://jsonplaceholder.typicode.com/posts/1`,
fetcher
)
if (error) return '読み込み失敗'
if (!data) return '読み込み中...'
return data.title
}ルート遷移はクライアント側で発生するため、従来のSPAのように動作します。例えば、以下のインデックスルートはユーザーがクライアント上で異なるポストにナビゲートできるようにします。
import Link from 'next/link'
export default function Page() {
return (
<>
<h1>インデックスページ</h1>
<hr />
<ul>
<li>
<Link href="/post/1">ポスト1</Link>
</li>
<li>
<Link href="/post/2">ポスト2</Link>
</li>
</ul>
</>
)
}画像最適化
next/imageによる画像最適化は、next.config.js内でカスタム画像ローダーを定義することで、静的エクスポートで使用できます。例えば、Cloudinaryなどのサービスで画像を最適化できます。
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export',
images: {
loader: 'custom',
loaderFile: './my-loader.ts',
},
}
module.exports = nextConfigこのカスタムローダーは、リモートソースから画像を取得する方法を定義します。例えば、以下のローダーはCloudinaryのURLを構築します。
export default function cloudinaryLoader({
src,
width,
quality,
}: {
src: string
width: number
quality?: number
}) {
const params = ['f_auto', 'c_limit', `w_${width}`, `q_${quality || 'auto'}`]
return `https://res.cloudinary.com/demo/image/upload/${params.join(
','
)}${src}`
}その後、アプリケーション内でnext/imageを使用し、Cloudinary内の画像への相対パスを定義できます。
import Image from 'next/image'
export default function Page() {
return <Image alt="turtles" src="/turtles.jpg" width={300} height={300} />
}ルートハンドラー
ルートハンドラーはnext buildを実行する際に静的レスポンスをレンダリングします。HTTPのGET動詞のみがサポートされています。これはキャッシュされたデータまたはキャッシュされていないデータから静的HTML、JSON、TXTまたは他のファイルを生成するために使用できます。例えば:
export async function GET() {
return Response.json({ name: 'Lee' })
}上記のファイルapp/data.json/route.tsはnext build中に静的ファイルにレンダリングされ、{ name: 'Lee' }を含むdata.jsonを生成します。
受信リクエストから動的な値を読み取る必要がある場合は、静的エクスポートを使用できません。
ブラウザAPI
Client Componentsはnext build中にHTMLにプリレンダリングされます。window、localStorage、navigatorなどのウェブAPIはサーバー上では利用できないため、ブラウザで実行する場合のみこれらのAPIに安全にアクセスする必要があります。例えば:
'use client';
import { useEffect } from 'react';
export default function ClientComponent() {
useEffect(() => {
// これで`window`にアクセスできます
console.log(window.innerHeight);
}, [])
return ...;
}サポートされていない機能
Node.jsサーバーが必要な機能、またはビルドプロセス中に計算できない動的ロジックは、サポートされていません。
dynamicParams: trueを使用した動的ルートgenerateStaticParams()のない動的ルート- Requestに依存するルートハンドラー
- Cookies
- Rewrites
- Redirects
- Headers
- Proxy
- インクリメンタル静的再生成
- デフォルトの
loaderを使用した画像最適化 - ドラフトモード
- Server Actions
- インターセプティングルート
next devでこれらの機能を使用しようとすると、ルートレイアウトでdynamicオプションをerrorに設定した場合と同様のエラーが発生します。
export const dynamic = 'error'デプロイ
静的エクスポートを使用することで、Next.jsはHTML/CSS/JS静的アセットを配信できる任意のウェブサーバーにデプロイおよびホストできます。
next buildを実行すると、Next.jsは静的エクスポートをoutフォルダに生成します。例えば、以下のルートがあるとします。
//blog/[id]
next buildを実行した後、Next.jsは以下のファイルを生成します。
/out/index.html/out/404.html/out/blog/post-1.html/out/blog/post-2.html
Nginxなどの静的ホストを使用している場合、受信リクエストから正しいファイルへの書き換えを設定できます。
server {
listen 80;
server_name acme.com;
root /var/www/out;
location / {
try_files $uri $uri.html $uri/ =404;
}
# これは`trailingSlash: false`の場合に必要です。
# `trailingSlash: true`の場合は省略できます。
location /blog/ {
rewrite ^/blog/(.*)$ /blog/$1.html break;
}
error_page 404 /404.html;
location = /404.html {
internal;
}
}バージョン履歴
| バージョン | 変更内容 |
|---|---|
v14.0.0 | next exportは"output": "export"に優先されて削除されました |
v13.4.0 | App Router(安定版)は拡張された静的エクスポートサポートを追加し、React Server ComponentsおよびRoute Handlersの使用を含みます |
v13.3.0 | next exportは非推奨であり、"output": "export"に置き換えられました |