仕組み
staticモードとserverモードの主な違いは、同じリクエストハンドラをビルドのときに呼ぶか、リクエストのたびに呼ぶかです。モードごとにエラーになるものも、この違いで変わります。
このページの内容
モードの指定
モードはframework()のmodeで決まります。どちらのモードでも、インストールするのは同じ@k8ordo/frameworkです。
routes/の書き方と'use client'の境界は、どちらのモードでも同じです。
ハンドラの呼ばれ方
mode: 'static'
vite build → handler(/products/1) → index.html
→ handler(/products/1/index.rsc) → index.rsc
mode: 'server'
request → handler(request) → Responseどちらのモードでも、vite buildはdist/rsc/index.jsにリクエストハンドラを書き出します。Requestを受け取ってResponseを返す関数です。
staticモードでは、ビルドの最後にページごとにHTMLとペイロードのためにハンドラを2回呼び、返ったResponseをindex.htmlとindex.rscに書き出します。リダイレクトするページはindex.htmlだけ、route.tsはGETのResponseを1つのファイルに書き出します。serverモードでは、リクエストのたびにハンドラを呼び、そのResponseを返します。
vite devは、どちらのモードでもリクエストのたびにハンドラを呼びます。そのためstaticモードでも、pathsに無い値のページが開発中は表示されます。fallback.tsxのあるページでは、その値にシェルが答えます。開発中とビルドのほかの違いはトラブルシューティングを見てください。
HTMLとペイロード
/products/1 → HTML
/products/1/index.rsc → RSC payloadどちらのモードでも、ページにはHTMLとRSCペイロードの2つの形があります。ペイロードは、ページのパスに/index.rscを付けたURLにあります。クライアント側の遷移では、このペイロードを取得します。
最初に開いたページでは、描画に使ったペイロードがHTMLに埋め込まれています。ハイドレーションはそれを読むので、同じページを2回取得しません。
staticモードでの拒否
vite buildstatic build cannot run guard.ts — a file has no request to guard, and these are guards:
src/routes/admin/guard.ts
this application wants mode: 'server'staticモードでも、@k8ordo/frameworkにはサーバー用の機能が含まれています。staticモードでそれを使うと、ビルドがエラーになります。
guard.tsとsearchをexportするページ、GET以外をexportするroute.tsは、ビルドを始める前にエラーになります。@k8ordo/framework/serverのimportと'use server'は、各環境をコンパイルしたあとにエラーになります。どちらも、ページを1つも書き出す前にエラーになります。
vite devでも、これらを使うモジュールをコンパイルした時点で同じエラーになります。開発中だけ動いて本番で何もしないコードは残りません。拒まれるものの一覧と理由はモードの選び方を見てください。
serverモードでの拒否
動いているサーバーは、どこからでもリクエストを受け取ります。ハンドラは、アプリが応答すべきでないリクエストを描画の前に拒みます。
- 別のオリジンからの
POST:ページとServer ActionへのPOSTは、Originが無いか別のホストを指すと403になります。別のサイトのフォームから、訪問者のCookie付きでServer Actionを呼ばせないためです。 GETとHEADとPOST以外のメソッド:ページへのリクエストなら、その3つをAllowに並べた405になります。- Viteの
baseの外のURL:アプリのURLには含まれないので、404になります。
共通のエラー
次のものは、どちらのモードでもエラーになります。
routes/の決まりに合わないファイルやディレクトリと、どのURLにも答えないルート- 非同期に検証する
paramsSchema(a params schema must validate synchronously) - Client Componentから読み込まれた
server-onlyのモジュール - ルートから始まらないViteの
base(./など)