Next.js 14.1 を GitHub Pages にデプロイするガイド
Next.jsで作成したプロジェクトは、
GitHub Actionsを使って、GitHub上にデプロイすることができます。
この記事では、GitHub Pagesにデプロイした手順と、遭遇したエラーについてまとめました!
検証環境:
・Next.js v14.1.3/ App Router
vercelの無料枠は、接続可能なGitHubリポジトリの数が3つまでなので、柔軟に使い分けできると良さそうですね!
1:Next.js/App Routerプロジェクトの作成
まずは、公式のinstallationに従い、以下のコマンドでNext.jsをインストールします。
npx create-next-app@latest
今回は、App Routerを使用し、
質問への回答はすべてデフォルトのまま進みます。
2:GitHub Pagesへのデプロイに必要な変更を加える
GitHubにプッシュする前に、2つ変更を加える必要があります!
①nextConfigファイルの変更
Next.js v14.1.3では、create-next-app
したら、
設定ファイルは、next.config.mjs
になっているはずです。
nextConfigに、静的エクスポートの設定を記述します!
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
+ output: "export",
}
export default nextConfig
ポイント:もし next.config.js を使う場合
nextConfigの設定は以下のようになります!
/** @type {import('next').NextConfig} */
const nextConfig = {
output: "export",
}
module.exports = nextConfig
設定ファイルが、next.config.js
か、next.config.mjs
かによって、
後述する変更が異なるので注意してください!
自分は、これに詰まりました。。
特に理由がなければ、デフォルトのnext.config.mjs
でOKだと思います!
これにより、next build
を実行すると、
./out
フォルダが生成され、静的サイトが出力されます!
メモ:next exportは非推奨→削除
ちなみに、
以前のPages Routerでは静的サイトを出力するには next export
コマンドを実行する必要がありました。
これは、v13.3.0で非推奨になり、nextConfigにoutput: "export"
の記述をする方法に置き換わりました。
そして、v14.0.0にて、next export
は削除されています!
詳しくは、下記のバージョン履歴をチェックしてみてください:
②ImageコンポーネントにbasePathの設定を記載する
GitHub Pagesにデプロイする場合、URLは以下のようになります:
https://[アカウント名].github.io/[リポジトリ名]/
このようなURLの場合、Next.jsで、basePath
の設定を行うことができます!
ドメインのサブパスの下にNext.jsアプリケーションをデプロイするには、basePath設定オプションを使用できます。
実は、後述するGitHub Actionsのワークフローファイルで、
basePath
をnextConfig
内に、自動で追加する処理が含まれています。
なので、今回は自分でnextConfig
内に、basePath
を設定する必要はありません!
ただし、Imageコンポーネントを使用する場合は、
上記のnextConfig
内の設定とは別で、src属性にbasePath
を追加する必要があります。
app/page.tsx内で、デフォルトで記載されているImageコンポーネントを、以下のように書き換えます!
import Image from 'next/image'
+ import nextConfig from "../../next.config.mjs";
+ const BASE_PATH = nextConfig.basePath || "";
...
<Image
+ src={`${BASE_PATH}/vercel.svg`}
alt="Vercel Logo"
className="dark:invert"
width={100}
height={24}
priority
/>
...
<Image
className="relative dark:drop-shadow-[0_0_0.3rem_#ffffff70] dark:invert"
+ src={`${BASE_PATH}/next.svg`}
alt="Next.js Logo"
width={180}
height={37}
priority
/>
ポイント:もし next.config.js を使う場合
上記のコードを、next.config.js
ファイルからのインポートに合わせる必要があります!
import nextConfig from "../../next.config.mjs";
const BASE_PATH = nextConfig.basePath || "";
↓
import { basePath } from "../../next.config.js";
const BASE_PATH = basePath || "";
これによって、Imageコンポーネントを使った画像が、適切に提供されます!
3:GitHub上にプッシュする
これに関しては、そのままですね!
コミットして、GitHub上にプッシュします!
GitHub Actionsのテンプレートに関しては、GitHub上で導入・編集できます!
4:GitHub Actionsのテンプレートを導入・編集
GitHub Pagesにデプロイするにあたって、
公式から提供されている、Next.js用のGitHub Actionsのテンプレートを利用できます!
これによって、main
ブランチへのプッシュをトリガーに、
ビルドとデプロイのプロセスを、自動化することが可能です!
以下の画像のように、リポジトリの画面から、
Settings > Pages > Next.jsテンプレートの「Configure」と進みます:
すると、Next.js用のGitHub Actionsのテンプレートファイル(nextjs.yml)の、編集画面が表示されます。
これは、現時点(2024/03/25)では、最新のNext.jsに合わせて更新されていないので、
少し変更を加える必要があります!
デフォルトの通りnext.config.mjs
を使っている場合、
以下のように、ハイライトされている2箇所を書き換えて、コミットします!
# Sample workflow for building and deploying a Next.js site to GitHub Pages
#
# To get started with Next.js see: https://nextjs.org/docs/getting-started
#
name: Deploy Next.js site to Pages
on:
# Runs on pushes targeting the default branch
push:
branches: ["main"]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
# Build job
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- 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 }}/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 Node
uses: actions/setup-node@v4
with:
node-version: "20"
cache: ${{ steps.detect-package-manager.outputs.manager }}
- 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
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') }}-${{ 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') }}-
- name: Install dependencies
run: ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }}
- name: Build with Next.js
run: ${{ steps.detect-package-manager.outputs.runner }} next build
- # - name: Static HTML export with Next.js
- # run: ${{ steps.detect-package-manager.outputs.runner }} next export
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./out
# Deployment job
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
もし、next.config.js
を使っている場合は、
下記の「1つ目の変更」を加える必要はありません!
変更点①:generator_config_file: next.config.mjs
Setup Pages
の中に、
generator_config_file: next.config.mjs
を追加しています!
- 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
この、Setup Pages
には、basePath
をnextConfig
内に、自動で追加する処理が含まれています。
つまり、ここの部分で、
実際のデプロイ先のURLhttps://[アカウント名].github.io/[リポジトリ名]/
を追加しています!
その際、注意すべきポイントが、generator_config_file: next.config.mjs
を指定しない場合、
標準でnext.config.js
ファイルを設定ファイルとして検出するようになっています。
next.config.mjs
を使用しているのに、上記の記載を追加しない場合、
next.config.js
ファイルが新たに作成されてしまい、エラーがスローされます!
変更点②:next export
先述した通り、App Routerではnext export
コマンドが不要なため、この2行は削除 or コメントアウトします!
- # - name: Static HTML export with Next.js
- # run: ${{ steps.detect-package-manager.outputs.runner }} next export
5:GitHub Pagesにデプロイ🚀
main
ブランチへコミットを行うと、自動的にGitHub Actionsが作動するので、
デプロイが完了するのを少し待ったら、完了になります👍
詰まったポイント)Error: Process completed with exit code 2.
Github Actionsのテンプレを使用して、デプロイする際に、以下のようなエラーに遭遇しました:
Run actions/upload-pages-artifact@v3
Run echo ::group::Archive artifact
Archive artifact
tar: out: Cannot open: No such file or directory
tar: Error is not recoverable: exiting now
Error: Process completed with exit code 2.
このエラーの内容は、
./out ディレクトリ(静的エクスポートされたディレクトリ)が見つからない、ということです。
つまり、next.config.mjs
に記述した、output: 'export',
が読み込まれていないということになります。
結論として、これは、Github Actions テンプレのワークフローのSetup Pages
が原因でした。。
そのSetup Pages
の箇所でやっていることは、
basePath(デプロイ先のPagesのURL)を、nextConfig
内に自動で挿入してくれるという処理です。
該当のActionsのソースコードを見に行って、原因がわかりました:
(上記よりコードを引用) case 'next':
// Next does not want a trailing slash
path = removeTrailingSlash(path)
return {
configurationFile: generatorConfigFile || './next.config.js',
blankConfigurationFile: `${__dirname}/blank-configurations/next.js`,
properties: {
// Configure a base path
basePath: path,
// Disable server side image optimization too
// https://nextjs.org/docs/api-reference/next/image#unoptimized
'experimental.images.unoptimized': true,
// No longer experimental as of Next.js v12.3.0
'images.unoptimized': true
}
}
上記では、Next.jsの設定ファイルに関して、
generatorConfigFile、または./next.config.js
となっています。
generatorConfigFileに関しては、別ファイルにて、generator_config_file
の値を読み取っていました。
(メモ:Actionsの入力は、core.getInputで読み取ることができます。詳しくは下記を参照)
つまり、Setup Pages
内部は次のような処理になっていました:
-
generator_config_file
が指定されていれば、それを設定ファイルとして検出し、そこにbasePathに関する情報を書き込む。 - もし、何も指定されていなければ、
./next.config.js
に書き込む。
create-next-app
では、next.config.mjs
がデフォルトで作成されます。
なので、next.config.mjs の場合は、下記のオプションを指定しないといけません。
generator_config_file: next.config.mjs
この指定をしないと、next.config.mjsがあるのに、next.config.jsが作成されてしまい、元のnext.config.mjsの内容が反映されなくなります!
テンプレを使う際は、ちゃんと調べることが大切ですね!
おわりに
最後まで読んでいただきありがとうございます🐸
現時点(Next.js V14.1.3)では、create-next-app
で、next.config.mjs
がデフォルトで作成されるので、Actionsのテンプレートの変更には、注意が必要ですね!
気がついたら結構長くなっていましたが、
ぜひ、GitHub Pagesでのデプロイを試してみてください!
Happy Hacking !
参考
Discussion