Next.jsのApp RouterでStatic Exportsをする時はDynamic Routesのバグに気を付ける必要がある
created at
updated at
表題の通り、2024/11/17時点の最新版であるNext.js 15.0.3ではApp RouterでStatic Exports(いわゆるSSG)を使用するとDynamic Routesで複数のバグがあるので回避策を入れる必要がある。
next devでDynamic Routesを使う時はパーセントエンコードが必要
Static ExportsでDynamic Routesを使用する時は
generateStaticParams()
でパスを定義しておく必要があるが、next dev
では generateStaticParams()
の結果はパーセントエンコードしないとエラーが出てしまう。これは仕様に記載されていないし、next build
の時は逆にパーセントエンコードするとエラーになってしまうので、next dev
の時にバグっているっぽい。そのため、次のようにして
next dev
の場合と next build
の場合で generateStaticParams()
の返り値を切り替える必要がある_
tsexport async function generateStaticParams(): Promise<
{
slug: string[]
}[]
> {
const slugs = await getSlugs()
return slugs.map((slug) => ({
slug: [
process.env.NEXT_PHASE === PHASE_PRODUCTION_BUILD
? slug
: encodeURIComponent(slug),
],
}))
}
process.env.NEXT_PHASE
はNext.jsが自動的に定義してくれる環境変数で、next build
時は PHASE_PRODUCTION_BUILD
が設定される事になっている。この環境変数を使って next build
時はそのまま、それ以外の時(= next dev
)は encodeURIComponent()
を通してパーセントエンコードしたものを返すようにすればよい。この事象はDynamic Routes with generated segment values containing characters that need to be URI encoded return 404 in dev · Issue #63002 · vercel/next.js · GitHub で報告されており、fix: uri encode dynamic routes in dev by samcx · Pull Request #71588 · vercel/next.js · GitHubで修正されたっぽいが、2024/11/17時点ではリリースされていないので↑のような回避策を取る必要がある…
next devでDynamic Routesのcatch-allを使う時は/で分割してはいけない
Dynamic Routesでcatch-allを使う時に仕様ではparamsは
/
ごとに分割した文字列の配列を渡す必要があるのだが、上記のバグ関連で next dev
では パスが/複数/あります
のように /
を含んでいる場合に 38391 E382 B9 E3818C/ E8 A487 E695 B0/ E38182 E3828A E381 BE E38199
のような形で E/
以外をパーセントエンコードしつつ1つの文字列として返さないといけないバグがある。もし文字列を
/
で分割してしまったり、/
もパーセントエンコードしてしまうと、パス不一致のエラーが出てしまうので、次のようにして回避する必要がある_
tsexport async function generateStaticParams(): Promise<
{
slug: string[]
}[]
> {
const slugs = await getSlugs()
return slugs.map((slug) => ({
slug: [
process.env.NEXT_PHASE === PHASE_PRODUCTION_BUILD
? page.title.split('/')
: [
page.title
.split('/')
.map((p) => encodeURIComponent(p))
.join('/'),
],
],
}))
}
こちらはIssueが無さそうだが、多分上記のバグ修正でなおりそうな気がする…
結論
アセット収集機能とかもないので、SSGしたいならNext.js以外を使ったほうがいいです