app directoryで「HTML」を忘れてもビルドが通るが動かないぞ(v13.1.6)
Next.jsのapp
directoryがどんどん更新され、v13.2
ではSEO用にmetadata
が設定可能になるなど、ワクワクなことが沢山だ!
しかし、まだまだエラーの対処法の情報が少ない。筆者は、ルートのHTMLタグを忘れるという根本的なミスを犯してしまったのに、ビルドが通ってしまい、原因にたどり着けず時間を浪費してしまった。
状況
- Next.js v13.1.6
問題のファイルがこちら
import Footer from '@/components/Footer';
import Header from '@/components/Header';
import { ReactNode } from 'react';
import '@/styles/globals.css';
export default async function Layout({ children }: { children: ReactNode }) {
return (
<>
<Header />
<div className="container">{children}</div>
<Footer />
</>
);
}
これは app/layout.tsx
なので、何もしなければ全ページで使われるレイアウトである。
v13.1.6
現在、ローカルでは表示できるし、ビルドも通ってしまう。だが、根本的に間違えている。
正解
import Footer from '@/components/Footer';
import Header from '@/components/Header';
import { ReactNode } from 'react';
import '@/styles/globals.css';
export default async function Layout({ children }: { children: ReactNode }) {
return (
+ <html lang="ja">
+ <body>
<Header />
<div className="container">{children}</div>
<Footer />
+ </body>
+ </html>
);
}
html
とbody
を忘れていた。
The root layout must define <html> and <body> tags since Next.js does not automatically create them.
ドキュメントには「必ず書くように」と書いてあるので、忘れていた俺が悪いのだが...
指摘と現状
We could however provide a better warning for this type of error, so we are keeping this issue to track.
HTMLとBODYが無いですよというイシューが立っていて、「layout.tsxがそれらを返さないといけないんですよ」「でも、より良い警告が出せるだろうから」とオープンのままになっている。
エラーでググれるように経緯を書くぜ
もし英語のエラーでググってもこの記事がヒットするように、経緯を書こうと思う。
ビルド結果を動かすと、一切の描画に失敗する現象に遭遇した。エラー内容:
-
Uncaught Error: Minified React error #418; visit https://reactjs.org/docs/error-decoder.html?invariant=418 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.
DOMException: Failed to execute 'appendChild' on 'Node': Only one element on document allowed.
とにかくハイドレーションに失敗している。この手のエラーは主に以下の原因が多い。
- HTML構造に誤りがある
- サーバーとクライアントで齟齬が生じるロジックがある
- もっぱらDateに関するミスが多い
そういえば、表示できているからと、コンソールをしっかり読まずにビルドしていた。
ちゃんとローカルのコンソールを見ると、invariant expected app router to be mounted
という警告が出ていた。
このエラーで調べることで、ようやく html
とbody
を忘れている事に気づいたのだった。
Discussion