Get Started
@k8ordo/server を入れて vite.config.ts にプラグインを 1 つ足し、routes/ にレイアウトとページを置けば、vite build の出力を serve() が動かします。このページはそこまでの最短の道筋と、このモードを選ぶことが何を意味するかを説明します。
モードは依存で決まる
このパッケージを入れることが、アプリを「動くもの」にすることです。リクエストのたびに描画して答えるので、パラメータの値を列挙する必要がなく、知らない URL は本物の 404 になり、フォームは Server Action に届きます。
もう一方の @k8ordo/static は、全ルートをビルド時に描いてファイルを出荷します。両者のあいだでアプリのほかの部分は何も変わりません。ルートの文法も、境界も、リクエストハンドラも同じで、ハンドラがリクエストごとに呼ばれるか、ビルド時にルートごとに呼ばれるかだけが違います。プラグインが両方のパッケージで framework() という名前なのはそのためで、モードを決めるのは import だけです。
インストール
@k8ordo/server は実行時の依存です。デプロイしたアプリが動かすのは serve() とビルドされたハンドラだからです。@k8ordo/server はプラグインで Vite を読みますが、アプリのコードが import する serve()・redirect()・型は Vite を読まない @k8ordo/server/runtime から来るので、vite は開発時の依存で足ります。server-only は、サーバー専用のモジュールに付ける import を TypeScript が解決できるようにするためのものです。
npm install @k8ordo/router @k8ordo/server react react-dom server-only
npm install -D viteピア依存と、ビルドとサーバーを動かす Node.js の要件です。
- @k8ordo/router
- React >= 19.3.0
- React DOM >= 19.3.0
- Vite >= 8.2.1
- Node.js >= 24
vite.config.ts
プラグインは framework() 1 つです。オプションは routesDir(ルートのディレクトリ、既定は src/routes)だけです。
// vite.config.ts
import { framework } from '@k8ordo/server';
import { defineConfig } from 'vite';
export default defineConfig({ plugins: [framework()] });framework() は Vite のプラグインの配列を返し、その中に React のプラグイン(Fast Refresh)と RSC のパイプラインがすでに入っています。@vitejs/plugin-react を自分で足す必要はありません。
tsconfig.json
型の配線を効かせるには、tsconfig.json の include に .k8ordo をグロブで書きます。.k8ordo はドットで始まるので、ディレクトリ名だけを書いた include は黙ってそれを飛ばします。飛ばされてもビルドは通り、href が表に対して検査されなくなるだけです。
{
"include": ["src/**/*.ts", "src/**/*.tsx", ".k8ordo/**/*.ts"]
}最小の routes/
ルートレイアウトが <html> と <body> を描きます。フレームワークは文書のテンプレートを持ちません。見えないテンプレートは、変えられないテンプレートだからです。ディレクティブの無いファイルは Server Component です。
// src/routes/layout.tsx
import type { ReactNode } from 'react';
export default function RootLayout({ children }: { children: ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}// src/routes/page.tsx
export default function HomePage() {
return (
<>
<title>home</title>
<h1>hello</h1>
</>
);
}ルートレイアウトは文書そのもの
hydration は文書の全体を照合します。フレームワークが書いた HTML とブラウザのあいだで、HTML を書き換えるもの、たとえば Web フォントをインライン化したり、メールアドレスを難読化したり、スクリプトを遅延させたりする CDN は、React が照合しようとしている木を変えてしまい、その差分で hydration が失敗します。影響を受けない方法は、そうしたサービスに書き換える余地を与えないことです。アセットは別のオリジンから読まず、同じオリジンから配信します。
動かす
vite dev は本番と同じパイプラインで、Fast Refresh も効きます。vite build が dist/ を書き、serve() を呼ぶ小さなスクリプトがそれを動かします。
// serve.js
import { serve } from '@k8ordo/server/runtime';
await serve({ port: 3000 });vite dev
vite build
node serve.js生成されるもの
最初の vite dev か vite build が .k8ordo/ を書きます。ルート表(routes.gen.ts)、それを @k8ordo/router に結ぶ型の配線(register.gen.ts)、そして自分自身を git から外す .gitignore です。
vite build は型を検査しません。satisfies による検査の結果を出すのは tsc です。.k8ordo/ は git に入らないので、新しいチェックアウトでは tsc の前に一度 vite dev か vite build を走らせて書かせます。
中身と、ビルドが拒むものは、リンク先にあります。 routes/
@k8ordo/static を選ぶとき
リクエストを必要とするものが 1 つも無いなら、@k8ordo/static が同じアプリをファイルに書き出し、サーバーを動かし続ける必要はなくなります。次のどれも要らないアプリがそれに当たります。
- フォームの送信先になる Server Action と、そこからの
redirect() - ページがリクエストのヘッダーや cookie を読むこと
- アプリ自身が返す本物の 404
- 前もって列挙できないパラメータの値