転職用のポートフォリオとして、個人でWebアプリ「Hubpin」を作っています。
制作の経緯は「Hubpin 開発記録」に時系列でまとめています。
設計と判断は自分で行い、実装も原則自分で書いています。AIには手順書・レビュー・調査を任せています。
前回は use server が何を宣言していたのかという話でした。
今回は、その並びで長く誤解していた記号の話です。
公開ページを静的化する作業をしていて、npm run build の出力をよく見るようになりました。
各ページの先頭にこういう記号が付きます。
┌ ○ /
├ ○ /_not-found
├ /[username]
├ ● /matsutake
├ ● /guest
├ ƒ /dashboard
└ ○ /login
ƒ は Dynamic の印です。
このとき自分は「動的ということはブラウザで描画される、つまり Client Component のことだろう」
と読んでいました。CSR という言葉とも結びついていたと思います。
反例が、自分のビルド出力の中にありました
上の出力をもう一度見て止まりました。
○ /login です。
このページは "use client" を書いたフォームを含んでいます。
数日前に自分で書いたので、間違えようがありません。
Client Component を含むページが、静的に焼けている。
自分の読み方が間違っていることが、自分の出力の中に写っていました。
3つの軸が混ざっていました
分けたらこうなりました。
| 軸 | 選択肢 |
|---|---|
| いつHTMLを作るか | ビルド時(○ ●)/ リクエストのたび(ƒ) |
| どこで作るか | サーバー / ブラウザ |
| Server / Client Component | "use client" の有無 |
ビルド出力が言っているのは、1行目だけでした。
○ も ● も ƒ も、HTMLを作っているのはサーバーです。
違うのは作るタイミングのほうでした。
そして "use client" は「ブラウザでも動く」という意味であって、
「サーバーで描画しない」ではありません。
Client Component もサーバーで初回のHTMLを作ってから、ブラウザへ渡されます。
3つとも同じページについて、それぞれ別に決まります。
では ƒ を決めているのは何か
/dashboard が ƒ なのは、"use client" があるからではありませんでした。
このページはログイン中のユーザーを確かめるために Supabase のクライアントを作っていて、
その中で cookies() を読んでいます。
誰がアクセスしたかで中身が変わるので、ビルド時にHTMLを作れません。
判定はここだけでした。
リクエストごとに答えが変わるか。
誰が見ても同じHTMLでいいなら焼ける。
見る人によって変わるなら焼けない。それだけの話でした。
/login が焼けるのは、誰が開いても同じフォームが出るからです。
中の "use client" は、焼けるかどうかに関係していません。
なぜ混ざったのか
「Client Component」「CSR」「動的」が、全部同じ方向の言葉に見えたからだと思います。
どれも「ブラウザ寄り」という気配があります。
実際には、"use client" は書ける場所の話で、ƒ は焼けるかどうかの話でした。
知らない単語なら調べます。
知っている単語が並んでいると、そのまま自分の文脈で読んでしまう。
おわりに
この誤解が解けたのは、他人の説明を読んだからではありませんでした。
数日前に自分で書いたコードが、反例としてビルド出力に並んでいたからです。
記号の意味を調べるより、○ /login の1行を見て止まったほうが早かった。
自分の出力の中に答えがあることは、わりとあるのだと思います。
次回は、この静的化を進めた結果、
壊れていないコードで CI が落ちた話を書きます。
