Next.js 14(+pnpm)でGitHub Pagesホスティング(+カスタムドメイン)
Next.js 14(+pnpm)で作成したWebアプリケーションをGitHub Pagesにホスティング(+カスタムドメイン構成)した際のノウハウメモです(2024年9~10月現在)。
それぞれの対処からしばらく経ってしまい、記憶と気力が怪しいので補足のためしばらく随時更新するかもしれません。
Next.jsで作成したWebアプリケーションを静的サイト生成(SSG: Static Site Generation)する際の情報になります。
開発資産の修正点
app/layout.tsx
import "./globals.css";
以下に修正します。
import "@/app/globals.css"
修正しないと静的サイト生成したHTMLからCSS/JavaScriptへのリンクに”/<GitHubリポジトリ名>
“が入ってしまうための対処になります。カスタムドメインを利用しない場合は修正不要と思われます。
next.config.mjs
import { readFileSync } from 'fs';
import { join } from 'path';
const packageJsonPath = join(process.cwd(), 'package.json');
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
const isDev = process.env.NODE_ENV === 'development';
const nextConfig = {
output: isDev ? undefined : 'export',
env: {
APP_VERSION: packageJson.version,
},
experimental: {
missingSuspenseWithCSRBailout: false,
},
};
例示した内容には3つの要素が含まれています。
- 静的サイト生成のための設定
- 変数
isDev
の設定およびoutput
ディレクティブ
- 変数
useSearchParams (next/navigation)
を静的サイトで使用するための設定(Next.js 14時点)experimental/missingSuspenseWithCSRBailout
ディレクティブuseSearchParams
(クエリパラメタ参照)を実装で使用していないのであれば不要(Suspense
が効かないなど副作用があります)
package.json
に記述されているversion
をアプリ内から環境変数APP_VERSION
で参照するための設定- 上記以外の記述
静的サイト生成のための設定にフォーカスして説明しますと、output: 'export'
が静的サイト生成をするために最低限必要な設定です。ただしこれだけですと、通常の開発時にも静的サイト生成が行われてデバッグしにくいため、開発時は静的サイト生成が行われないようにしています。環境変数NODE_ENV
の値が'development'
ならば開発ビルドと判断し、output
ディレクティブでundefined
を指定するようにしています。
pnpm run build
を実行した場合はout
フォルダに静的サイトのビルド出力が行われますので、静的サイト生成された場合の内容を確認することもできます。ただし画像やCSS参照パスの違い等により画面表示が崩れることがありますので動作確認には向かないでしょう。
(Imageコンポーネントを利用している.tsx) ※カスタムドメインを使用しない場合
import nextConfig from '@/next.config.mjs'; // .mjsは省略できない
const BASE_PATH = nextConfig.basePath || '';
:
<Image src={`${BASE_PATH}/...`}
GitHub Pagesのようにデプロイ先がサーバルートでない(URLが”https://<GitHubアカウント名>.github.io/<リポジトリ名>/
)場合、Image
コンポーネントのsrc
属性のパスを調整する修飾設定を行う必要があります。上記のように設定するとBASE_PATH
にリポジトリ名が設定されますので、実際に画像ファイルが存在するパスへの解決が行われます。
ただしカスタムドメインでデプロイ先がサーバルートとなる場合は逆に不一致となりますので、この修正は不要となります。
GitHub Actionsの構成
開発資産をGitHubリポジトリにpushした際に静的サイトが生成されるようにGitHub Actionsを構成します。GitHubによって提示されるActionsのテンプレート内容は時期により異なりますので、状況に応じて適宜対応する必要があります。以下の記述は2024年9月実施時点での内容になります。
GitHubリポジトリページ > Settings
> Code and automation
> Pages
GitHub Pages
> Build and deployment
> Source
プルダウンからGitHub Actions
を選択
“Next.js
“の”Configure
“ボタンを選択(表示されていない場合はプルダウンの下にある”browse all workflows
“リンクを選択し、”Next.js
“を検索)
リポジトリ配下に.github/workflows/nextjs.yml
というYAMLファイルを作成するためのテンプレートが展開された編集画面が表示されます。エディタ中のbuild
セクション配下で”name: Setup Node
“のセクションを探し、配下の”node-version
“を使用しているNode.jsのバージョンに合わせます。使用しているバージョンは開発環境でnode --version
コマンドにより確認することができます。またpnpm
を使用している場合は配下のwith
セクションに”cache-dependency-path: ./pnpm-lock.yaml
“を追記する必要があります。
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20"
cache: ${{ steps.detect-package-manager.outputs.manager }}
cache-dependency-path: ./pnpm-lock.yaml
pnmp
を使用している場合は”name: Detect package manager
“のセクション配下にpnpm
を検出するための条件分岐を追記する必要があります。package.json
より先に検出される必要があるため、追記位置に注意します。
- name: Detect package manager
id: detect-package-manager
run: |
if [ -f "${{ github.workspace }}/yarn.lock" ]; then
echo "manager=yarn" >> $GITHUB_OUTPUT
echo "command=install" >> $GITHUB_OUTPUT
echo "runner=yarn" >> $GITHUB_OUTPUT
exit 0
elif [ -f "${{ github.workspace }}/pnpm-lock.yaml" ]; then
echo "manager=pnpm" >> $GITHUB_OUTPUT
echo "command=install --frozen-lockfile" >> $GITHUB_OUTPUT
echo "runner=pnpm" >> $GITHUB_OUTPUT
npm install -g pnpm
exit 0
elif [ -f "${{ github.workspace }}/package.json" ]; then
echo "manager=npm" >> $GITHUB_OUTPUT
echo "command=ci" >> $GITHUB_OUTPUT
echo "runner=npx --no-install" >> $GITHUB_OUTPUT
exit 0
else
echo "Unable to determine package manager"
exit 1
fi
"name: Setup Pages
“セクションのwith
配下に”generator_config_file: next.config.mjs
“を追記します。これに関連して同様の解説記事によっては”name: Static HTML export with Next.js
“セクションをコメントアウトするように説明されていますが、2024年9月時点でのActionsテンプレートには存在しませんでしたので対応不要でした。
name: Setup Pages
uses: actions/configure-pages@v4
with:
# Automatically inject basePath in your Next.js configuration file and disable
# server side image optimization (https://nextjs.org/docs/api-reference/next/image#unoptimized).
#
# You may remove this line if you want to manage the configuration yourself.
static_site_generator: next
generator_config_file: next.config.mjs
“name: Restore cache
“セクションのwith
配下の記述行に”**/pnpm-lock.yaml
“を追記します(2か所)
- name: Restore cache
uses: actions/cache@v4
with:
path: |
.next/cache
# Generate a new cache whenever packages or source files change.
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock', '**/pnpm-lock.yaml') }}-${{ hashFiles('**.[jt]s', '**.[jt]sx') }}
# If source files changed but packages didn't, rebuild from a prior cache.
restore-keys: |
${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock', '**/pnpm-lock.yaml') }}-
“Commit changes...
“ボタンを選択し、以上の修正をコミットします。
GitHub Actionsの実行確認方法
mainブランチにpushするとActionsが実行されてビルド(静的サイト生成)が実施されます。
実行状況はリポジトリの”Actions
“メニューで確認できます。
カスタムドメインの設定を行う前や、カスタムドメインの設定を行わない場合では、”https://<GitHubアカウント名>.github.io/<リポジトリ名>/
“へアクセスすることにより生成された内容を参照することができます。ただしカスタムドメイン設定予定でImage
のbasePath
修飾をしていない場合は画像が表示されないなど表示は崩れます。逆にカスタムドメインを行なわず(github.io/<リポジトリ名>/
)にImage
のbasePath
修飾をしたのに表示が崩れる場合はこれまでの設定のいずれかが誤っている可能性があります。
カスタムドメインの構成
生成した静的サイトをgithub.ioではなくカスタムドメインにする場合の方法の説明になります。以下でGitHub設定を行う前にDNS設定を行うと、第三者によるドメインの乗っ取りが行われるタイミングが生じるとのことで御注意ください。
カスタムドメインのためのGitHub設定
GitHubリポジトリページ > Settings
> Code and automation
> Pages
Build and deployment
> Custom domain
入力欄にカスタムドメインを指定して”Save
“ボタンを選択します。直後にDNSチェックが走り、少しするとエラー表示がされます。解説記事によっては設定したドメイン文字列が含まれる”CNAME
“というファイルがリポジトリにコミットされ、カスタムドメインでの動作に必要で、GitHub Actionsによるデプロイではファイルが生成されないので別途対応が必要との情報もありましたが、自分の確認範囲ではファイルが無くても動作しました。
カスタムドメインのためのDNS設定
カスタムドメインがGitHub Pages(github.io
)を指すようにDNS CNAMEレコードを構成します(以下DNSレコード設定のイメージ)。
<カスタムドメイン> CNAME <GitHubアカウント名>.github.io
DNS設定後のカスタムドメインのためのGitHub設定
DNS設定を行った後、GitHub設定に戻りCustom domain
の”Check again
“ボタンをクリックします。DNS設定の認識状況によりますので、時間の経過後のリトライが必要になる場合もあります。Check結果がOKになりますと、元のhttps://<GitHubアカウント名>.github.io/<リポジトリ名>/
へのアクセスもカスタムドメインへリダイレクトされるようになります。
前述しましたようにGitHub Actionsでのビルド時にbasePath
にリポジトリ名が設定されるのはカスタムドメイン設定後も同様ですが、カスタムドメインではアプリケーションルートがサーバルートとなり、github.ioでのようにリポジトリ名パスが不要ですので、basePath
修飾は不要(修飾すると逆にパスが合わなくなる)になります。
HTTPS強制化
カスタムドメイン設定後、サーバ証明書が発行されるまで時間がかかりますので、”Enforce HTTPS
“のチェックボックスが有効(クリック可能)になるまで待ち、有効化されたらチェックしてHTTPS強制化を行います。チェック後Custom domain
での表示が”DNS Check in Progress
“にまたしばらくなるようです。
その他参考情報
静的サイト生成でのuseSearchParams(next/navigation)の使用
クエリパラメタを処理するためにuseSearchParams
を使用する場合、Next.js 14ではそのままでは静的サイト生成で動作しません。使用する場合は前述のようにnext.config.mjs
に”missingSuspenseWithCSRBailout: false
“を指定する必要があります(Next.js 14時点では実験的機能)。
ただしSuspense
が効かなくなるなどの副作用もあるようですので(詳細未確認)、注意して御利用ください。Next.js 15以降では正式に利用できるようになるかもしれないようです。
静的サイト生成ではRoute HandlersによるREST APIが(実用的)実装できない
正確にいうとRoute HandlersによるAPIエンドポイントは設けることができ、レスポンスも返すことができますが、クエリパラメタが処理できません。request.nextUrl.searchParams
でパラメタ値が取得できないため、パラメタ指定に応じたレスポンスを返すことができず、エンドポイントごとに固定のレスポンスとなるため、実用的な実装ができない状況になります。
Visual Studio Codeでのデバッグ(ステップ実行等)
.vscode/launch.json
に以下の記述をすることにより、ローカル(localhost:3000
)でのデバッグ実行ができ、VSCode上のブレークポイント設定やステップ実行、変数値参照等が行えます。自分が試した限りでは”Next.js: debug server-side
“をまず実行し、”Next.js: debu client-side
“をその後実行することでGoogle Chromeが起動されデバッグをすることができました。”Next.js: debug full stack
“については正常動作を確認できていません。
{
"version": "0.2.0",
"configurations": [
{
"name": "Next.js: debug server-side",
"type": "node-terminal",
"request": "launch",
"command": "pnpm run dev"
},
{
"name": "Next.js: debug client-side",
"type": "pwa-chrome",
"request": "launch",
"url": "http://localhost:3000",
"resolveSourceMapLocations": [
"${workspaceFolder}/", "!/node_modules/", "!/.next/**"
]
},
{
"name": "Next.js: debug full stack",
"type": "node-terminal",
"request": "launch",
"command": "pnpm run dev",
"console": "integratedTerminal",
"serverReadyAction": {
"pattern": "started server on .+, url: (https?://.+)",
"uriFormat": "%s",
"action": "debugWithChrome"
}
}
]
}
未解決の問題
- app/layout.tsxのheadにGoogle Analyticsタグを記述しても静的サイト生成されたページではbodyに配置される。
適用例
これまでの情報を適用した例として手前味噌になりますがWebアプリケーション「Re:将棋thread」ソースリポジトリを示します。稚拙な実装ですが御参考まで。
https://github.com/bills-appworks/bsky-shogithread-replay
主な参考情報
- pnpm + Next.js SSG で作成したページを GitHub Pages にデプロイする | Naoki’s Blog
- Next.js 14.1 を GitHub Pages にデプロイするガイド
- 2023年8月版: Next.jsをGitHub ActionsでGitHub Pagesにデプロイする方法
- Next.js で作ったサイトを GitHub Pages で公開する方法を爆速で丁寧に説明する #Node.js – Qiita
- GitHub PageとNext.jsで静的ページを構築 | SIOS Tech. Lab
- 2024年2月 GitHub Actions を使用したNextjs プロジェクトのGitHub Pages公開 #Next.js – Qiita
- GitHub Pages サイトのカスタムドメインを設定する – GitHub Docs
- カスタムドメインとGitHub Pagesについて – GitHub Docs
- GitHub Pages サイトのカスタムドメインを管理する – GitHub Docs
- GitHub Pages サイトの公開元を設定する – GitHub Docs
- HTTPS で GitHub Pages サイトを保護する – GitHub Docs
- Missing Suspense boundary with useSearchParams | Next.js
- Advanced Features: デバッグ | Next.js
1件の返信
[…] Next.js 14(+pnpm)でGitHub Pagesホスティング(+カスタムドメイン) […]