📝 Next.js App Router で Dynamic Routes が本番だけで404になるバグと向き合う
※ ただの私的なメモです。
Next.js のプロダクトにおいて、`src/app/[test]/page.tsx` という動的ルーティングのページを作る。
export default function ActivityPage({ params }: { params: { test: string } }) {
return <>{params.test}</>;
}
開発環境ではパス名が表示される
が、本番 (Vercel) では404エラーになる
面白いことに同ページでは favicon.ico のリクエストも404になる
ルートパスや動的パス以外の画面は、NextAuth の認証や tRPC の疎通含めて正常にできている
動的なパス設定の場合のみ。page コンポーネントに ClientSide コンポーネントを含めているとか関係ない
ただ、src/app/layout.tsx はその限りではない。ServerSide も ClientSide もごちゃ混ぜになっている。
import { type Metadata } from "next";
import "./globals.css";
import { TrpcProvider } from "./TrpcProvider";
import ThemeRegistry from "./ThemeRegistry";
import { ClientSessionProvider } from "./ClientSessionProvider";
import { font } from "./theme";
export const metadata: Metadata = {
title: "ルーティンナさん | Routinena",
description:
"「ルーティンナさん」はあなたの定期的なタスクを追跡し、最後にいつ完了したのかを簡単に記録できるWebアプリです。あなたの忙しい日常をサポートし、タスク管理を効率的にします。",
viewport: {
width: "device-width",
initialScale: 1,
maximumScale: 1,
},
themeColor: [
{ media: "(prefers-color-scheme: light)", color: "#FEFCF7" },
{ media: "(prefers-color-scheme: dark)", color: "#40221B" },
],
// PWA config
manifest: "/manifest.webmanifest",
// <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
// <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
// <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
icons: {
icon: [
{ url: "/icons/favicon-16x16.png", sizes: "16x16", type: "image/png" },
{ url: "/icons/favicon-32x32.png", sizes: "32x32", type: "image/png" },
],
apple: { url: "/icons/apple-touch-icon.png", sizes: "180x180" },
},
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="ja" suppressHydrationWarning>
<body className={font.className}>
<ClientSessionProvider>
<ThemeRegistry>
<TrpcProvider>{children}</TrpcProvider>
</ThemeRegistry>
</ClientSessionProvider>
</body>
</html>
);
}
Next.js Dynamic Routes ドキュメント
プレーン環境の試行
Issue を漁ってみたのは後でまとめるとして、最大の原因鑑別ということで、プレーンな Next.js の環境を用意して Vercel で公開してみると、期待通り動作した。どちらも現時点で最新バージョンの 13.4.10 を使っている
この鑑別から、 layout.tsx か create-t3-app でセットアップされた設定周りが怪しい
next.config.mjs はあまり変わらなかった。 `reactStrictMode: true` の指定が新たに入っていたが、消しても改善せず
関連 Issue
現状オープンな関連していそうな Issue はこれ
結論解決はされていないっぽいし原因も特定されていない?みたいだ。回避策としては以下の記述が見つかる
他にも関連しそうな Issue はあったが、どれも関係なさそうだった
原因は i18n の設定だった
と思ったら解決した。create-t3-app で指定されていた i18n の設定だった。
/**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful
* for Docker builds.
*/
await import("./src/env.mjs");
/** @type {import("next").NextConfig} */
const config = {
reactStrictMode: true,
/**
* If you have `experimental: { appDir: true }` set, then you must comment the below `i18n` config
* out.
*
* @see https://github.com/vercel/next.js/issues/41980
*/
i18n: {
locales: ["en"],
defaultLocale: "en",
},
};
export default config;
config.i18n を削除すると改善した
全然読んでなかったが appDir (App Routing) の環境では設定をコメントアウトするように注意書きがある・・・。開発環境で動くのが解せないが、書いてあるということはそうなんだろう。
斜め読みしたが今回の症状に対して直接的な記述はないように見受けられる。関連しそうな記述はここら辺か
同じ人から気になる記述が。404.tsx を追加したら治ったとのこと
Next.js のドキュメントはこれ
ただドキュメント通り not-found.tsx を作ったら本番ビルドでエラー (開発環境では通る)
Error: ENOENT: no such file or directory, open '/vercel/path0/.next/server/pages/ja/404.html'
Error: ENOENT: no such file or directory, open '/vercel/path0/.next/server/pages/en/404.html'
コメント通り 404.tsx に改名するとビルドは通ったが 404 エラー時の画面はデフォルトになる (コンポーネントが使用されない)。そして本番環境下で動的ルーティングが404になるエラーは改善しなかった。やはり next-config の i18n 設定が App Router に対応していない? か別仕様に変わったのかも知れない。直近では対応する予定がないのでここでは探りはしない
まとめ
ということで、原因は i18n の設定だった。本番だけで発生する症状だったので調べるのに手間取ってしまった
App Router (App Directory) は RSC の導入など、メリットが大きそうな一方でやはりというか当然のように破壊的な変更であった。もはや別フレームワークと認識した方が良いほどではないだろうか。それにしても良いが。
まだ周辺ライブラリの対応状況は実験的だったり追いついていないものが見受けられるが、 "use client"; ディレクティブでどうにかなる場合も多いので、やろうと思えば本番にも導入できるのではないだろうか。SSRが必須要件だった場合、かなりきつめの制約がいくつか発生するかも知れないが
この記事が気に入ったらサポートをしてみませんか?