@lazarv
react-server
どこでもReactを実行
サーバー、クライアント、ワーカー、エッジ環境でReactコンポーネントを実行する単一ランタイム — React Server Components、ストリーミング、デプロイを標準搭載。
コンセプト
ランタイムとしてのReact
Reactはブラウザの外で動作します。コンポーネントは実行可能なユニットであり、サーバー、ワーカー、エッジで実行されます。ランタイムが各コンポーネントの実行場所と方法を決定します。
ランタイムの境界はありません。Reactを書くだけで、同じモデルがどこでも機能します。コンポーネントはサーバーでデータを取得し、クライアントにHTMLをストリーミングし、ワーカースレッドで画像を処理できます — すべて同じ構文で。
"use client"、"use worker"、"use live" — たった一つのディレクティブでコンポーネントの実行場所を変更できます。ビルドステップの魔法も、別のAPIを覚える必要もありません。ランタイムがシリアライゼーション、ストリーミング、ハイドレーションを自動的に処理します。
つまり、アプリケーションはサーバーコード、クライアントコード、そしてその間のグルーコードのパッチワークではなく、一つの統一されたReactツリーです。パラダイムを切り替えることなく、単一ファイルから分散システムまでスケールできます。
Reactコンポーネントはもはや単なるUIではなく、アプリケーションランタイムの実行可能なユニットです。
サーバーコンポーネント — サーバー上で実行。データベースやAPIに直接アクセスし、クライアントバンドルのコストはゼロ。
export default async function Page() {
const data = await db.query("SELECT ...");
return <Feed items={data} />;
}
クライアントコンポーネント — ブラウザでハイドレート。おなじみのReactそのもの。
"use client";
export default function Counter() {
const [n, setN] = useState(0);
return <button onClick={() => setN(n + 1)}>{n}</button>;
}
ワーカー — バックグラウンドスレッドで実行。サーバーやUIをブロックせずに重い処理をオフロード。
"use worker";
export async function resize(buf) {
return sharp(buf).resize(800).toBuffer();
}
ライブコンポーネント — WebSocket経由で更新をストリーミング。各yieldが新しいReactツリーをクライアントに送信。
"use live";
export default async function* Price({ symbol }) {
while (true) {
yield <span>{await getPrice(symbol)}</span>;
await new Promise((r) => setTimeout(r, 1000));
}
}
@lazarv/react-server は、サーバー、クライアント、ワーカー、エッジ環境でReactコンポーネントを実行するためのランタイムです。
ファイルを1つ作成 — それがアプリ全体です。設定もボイラープレートも不要。npx @lazarv/react-server ./App.jsx で起動。
export default function App() {
return <h1>Hello World!</h1>;
}
スケールする準備ができたら、app/page.jsx にページを追加してエントリーポイントを省略。ファイルシステムルーターが自動的に引き継ぎます。
export default async function Home() {
const posts = await db.posts.findMany();
return (
<main>
<h1>Blog</h1>
{posts.map((post) => (
<article key={post.id}>
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
</article>
))}
</main>
);
}
理念
なぜ @lazarv/react-server なのか?
ほとんどのReactフレームワークやメタフレームワークは、最初のコンポーネントを書く前に大量のセットアップが必要です。@lazarv/react-server は異なるアプローチを取ります — node でスクリプトを実行するように簡単ですが、React向けです。
単一ファイルから始めて、ニーズの成長に合わせてファイルシステムルーティング、キャッシング、静的生成、マルチランタイムデプロイを備えたフル機能アプリケーションにスケールできます。
即座のHMRを実現するVite搭載。Reactを同梱しているのでプロジェクトは軽量。Node.js、Bun、Denoをサポート。ビルトインアダプターでVercel、Netlify、Cloudflareなどにデプロイ可能。
数秒で開始
依存関係1つ。ファイル1つ。コマンド1つ。
クイックスタート
インストール&実行
依存関係を1つ追加し、Reactコンポーネントをエクスポートする .jsx ファイルを作成し、開発サーバーを起動します。それだけで完全なSSRとホットモジュールリプレースメントが動作します — ボイラープレートは不要です。
Reactをインストールする必要すらありません。ランタイムにバンドルされており、常に最新の状態に保たれています。
単一の依存関係でランタイムをプロジェクトに追加 — Reactは含まれており、別途インストール不要。
pnpm add @lazarv/react-server
デフォルトエクスポートされたReactコンポーネントを記述。このファイルがアプリケーション全体のエントリーポイント。
export default function App() {
return <h1>Hello World!</h1>;
}
Viteによる即座のホットモジュールリプレースメントで開発サーバーを起動。
pnpm react-server ./App.jsx
インストールを完全にスキップ — npxで任意のReactファイルを直接実行。実験やプロトタイピングに最適。
npx @lazarv/react-server ./App.jsx
ファイルシステムルーティング、レイアウト、本番用設定を備えたアプリケーションをcreateパッケージで構築。
npx @lazarv/create-react-server
Viteによる即座のHMRで開発サーバーを起動。
react-server
最適化された本番ビルドを作成し、ビルトインの圧縮とクラスターモードで配信。
react-server build react-server start
その他の方法
さまざまな開始方法
npx でインストールを完全にスキップして任意のReactファイルをその場で実行できます — プロトタイピングやクイックデモに最適です。または、createパッケージを使用して、ファイルシステムルーティング、レイアウト、本番設定が事前に組み込まれたフルプロジェクトをスキャフォールドできます。
スキャフォールドされたプロジェクトには完全な開発ワークフローが含まれます:即座のHMRを備えた開発サーバー、最適化された本番ビルドステップ、圧縮・キャッシング・クラスターモードを備えた本番サーバー — すべて react-server CLIで追加設定なしに利用可能です。
コア実行モデル
サーバーコンポーネント、クライアントインタラクティビティ、サーバー関数、ストリーミング — レンダリングの基盤。
デフォルトレンダリング
React Server Components
サーバーコンポーネントはサーバー上で実行され、async/await をサポートし、コードはクライアントに送られません。データベース、ファイルシステム、内部APIに直接アクセスできます — 別のバックエンドは不要です。
サーバー専用コンポーネントにはハイドレーションコストがありません。より高速なページ読み込み、より小さなバンドル、よりシンプルなアーキテクチャ。
export default async function Dashboard() {
const stats = await fetch(
"https://api.example.com/stats",
{ headers: { Authorization: `Bearer ${API_KEY}` } }
).then((r) => r.json());
return (
<section>
<h1>Dashboard</h1>
<p>Total users: {stats.users}</p>
<p>Revenue: ${stats.revenue}</p>
</section>
);
}
"use client";
import { useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Current count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
<button onClick={() => setCount(0)}>Reset</button>
</div>
);
}
インタラクティビティ
クライアントコンポーネント
"use client" を追加してインタラクティビティを有効にします。コンポーネントはまずサーバーでレンダリングされ高速な初期表示を実現し、その後クライアントで完全なフックとイベントハンドラのサポート付きでハイドレートされます。
ハイドレーションコストはインタラクティビティが実際に必要な場所でのみ発生します。それ以外はすべてサーバー専用のままです。
データミューテーション
サーバー関数
"use server" で任意のasync関数をサーバーサイドRPCエンドポイントに変換します。プログレッシブエンハンスメント付きのフォームアクションとして使用可能 — JavaScriptなしでもフォームが機能します。
APIルートの定義もfetchラッパーも不要です。ランタイムがシリアライゼーション、エラーバウンダリ、再検証を処理します。
async function createPost(formData) {
"use server";
const title = formData.get("title");
const body = formData.get("body");
await db.posts.create({ title, body });
revalidate("/posts");
}
export default function NewPost() {
return (
<form action={createPost}>
<input name="title" placeholder="Title" />
<textarea name="body" placeholder="Content" />
<button type="submit">Publish</button>
</form>
);
}
import { Suspense } from "react";
async function SlowData() {
const data = await fetchFromSlowAPI();
return <div>{data.result}</div>;
}
export default function Page() {
return (
<main>
<h1>Instant header</h1>
<p>This content appears immediately.</p>
<Suspense fallback={<p>Loading data...</p>}>
<SlowData />
</Suspense>
</main>
);
}
パフォーマンス
ストリーミングSSR
HTMLは利用可能になるとすぐにクライアントにストリーミングされます。<Suspense> と組み合わせることで、ページの一部がプログレッシブにレンダリングされ — ユーザーは遅いセクションがバックグラウンドで読み込まれる間、すぐにコンテンツを確認できます。
ストリーミングによる高速なTime-to-First-Byte。ハイドレーション完了後に完全なインタラクティブ体験。設定は不要です。
分散React
単一プロセスを超えたコンポーネント — ライブストリーミング、ワーカースレッド、マイクロフロントエンド。
リアルタイム
ライブコンポーネント
WebSocket経由のasyncジェネレータによるサーバーからクライアントへのストリーミング。各コンポーネントインスタンスが独自の永続的なサーバーサイド実行コンテキストを持ちます。
"use live" を追加してasyncジェネレータをエクスポートするだけ。各 yield が新しいReactツリーをクライアントに送信します。ダッシュボード、フィード、モニタリングに最適です。
"use live";
export default async function* StockPrice({ symbol }) {
while (true) {
const price = await getPrice(symbol);
const trend = await getTrend(symbol);
yield (
<div>
<span className="text-2xl">${price}</span>
<span className={trend > 0 ? "green" : "red"}>
{trend > 0 ? "▲" : "▼"} {Math.abs(trend)}%
</span>
</div>
);
await new Promise((r) => setTimeout(r, 1000));
}
}
"use worker";
export async function processImage(buffer, options) {
// Runs in a Worker Thread — won't block
// the main server or the UI thread
const result = await sharp(buffer)
.resize(options.width, options.height)
.webp({ quality: options.quality })
.toBuffer();
return result;
}
並行処理
ワーカー
"use worker" でバックグラウンドスレッドに重い計算をオフロード。サーバーではWorker Threads、ブラウザではWeb Workersとして動作します。
引数と戻り値はRSC Flightプロトコルでシリアライズされ、React要素を直接返すことができます。完全なHMRサポート付き。
コンポジション
マイクロフロントエンド
独立してデプロイされたRSCアプリケーションを合成します。各リモートアプリはホストページにストリーミングされます。isolate でShadow DOMカプセル化を有効にし、スタイルのリークを防ぎます。
インポートマップで依存関係を共有。defer でノンブロッキングローディングを実現。エッジ配信用に静的ビルドとしてエクスポート可能。
import { RemoteComponent }
from "@lazarv/react-server/remote";
export default function App() {
return (
<main>
<h1>Host Application</h1>
<RemoteComponent
src="https://team-a.example.com/header"
/>
<RemoteComponent
src="https://team-b.example.com/widget"
isolate
defer
/>
</main>
);
}
プラットフォーム機能
ランタイム上に構築されたアプリケーション機能 — ルーティング、ナビゲーション、キャッシング、コンテンツ合成。
ルーティング
ファイルシステムルーター
エントリーポイントを省略すると、ランタイムがファイル構造に基づいてルーティングします。ページ、レイアウト、パラレルアウトレット、APIルート、ミドルウェア、エラーバウンダリ、ローディングステート — すべてが規約駆動です。
動的セグメント、キャッチオールルート、ルートグループ、型付きルート生成がビルトインで提供されます。
app/
├── layout.jsx # ルートレイアウト
├── page.jsx # /
├── about.jsx # /about
├── posts/
│ ├── page.jsx # /posts
│ ├── [id].jsx # /posts/:id
│ └── [...slug].jsx # /posts/*
├── (auth)/
│ └── login.jsx # /login (グループ化)
├── @sidebar/
│ └── page.jsx # パラレルアウトレット
├── loading.jsx # Suspenseフォールバック
├── error.jsx # エラーバウンダリ
├── (i18n).middleware.mjs # ミドルウェア
└── GET.api.server.mjs # GET /api エンドポイント
import { Link } from "@lazarv/react-server/navigation";
export default function Nav() {
return (
<nav>
<Link to="/" prefetch>Home</Link>
<Link to="/about" prefetch>About</Link>
<Link to="/posts" prefetch="viewport">
Posts
</Link>
</nav>
);
}
ナビゲーション
クライアントサイドナビゲーション
Link、Form、Refresh、ReactServerComponent によるSPAライクなトランジション。ホバーまたはビューポート進入時にプリフェッチ、エラー時にロールバック、特定のアウトレットに更新をスコープ。
useClient() によるプログラマティックナビゲーションはストリーミングアーキテクチャと統合されており、空白画面のトランジションはありません。
キャッシング
キャッシングと再検証
レスポンス、データ、コンポーネントの各レベルでの多層キャッシング。プラガブルドライバを備えたUnstorage上に構築。
revalidate() と invalidate() でオンデマンドに無効化。"use cache" ディレクティブで宣言的なTTLとタグベースの無効化を実現。
import { useResponseCache, useCache } from "@lazarv/react-server";
レンダリング済みレスポンス全体を30秒間キャッシュ — 後続のリクエストはレンダリングを完全にスキップ。
useResponseCache(30000);
複合キーで個別のデータフェッチをキャッシュ。各エントリは独自のTTLを持ち、個別に無効化可能。
const post = await useCache(
["posts", id],
() => fetchPost(id),
60000
);
"use cache" ディレクティブをファイルの先頭に配置して、宣言的なTTLとタグベースの無効化を実現。
"use cache; ttl=60; tags=posts"
ページシェルと静的コンポーネントはビルド時にプリレンダリングされ、エッジから即座に配信。
export default function ProductPage({ params }) {
return (
<main>
<StaticHeader />
<ProductInfo id={params.id} />
<DynamicReviews id={params.id} />
</main>
);
}
"use dynamic" でマークされた動的コンポーネントは、静的シェルが既に表示されている間にリクエスト時にストリーミングイン。
"use dynamic";
export default async function DynamicReviews({ id }) {
const reviews = await fetchReviews(id);
return (
<section>
{reviews.map((r) => <Review key={r.id} {...r} />)}
</section>
);
}
ハイブリッドレンダリング
部分的プリレンダリング
コンポーネントレベルで静的コンテンツと動的コンテンツを混在。静的シェルはビルド時にプリレンダリングされ、動的部分はリクエスト時にストリーミングイン。
"use dynamic" または "use static" でコンポーネントをマーク。静的部分はエッジから即座に配信され、動的データは読み込まれます。
コンテンツ
Markdown & MDX
.md と .mdx ファイルを完全なremark/rehypeプラグインサポートとカスタムコンポーネントオーバーライド付きでページとして直接使用。
Markdown内にReactコンポーネントを埋め込み可能。カスタムコンポーネントを一度定義すれば、すべてのレンダリングにグローバルに適用されます。
mdx-components.jsx でカスタムコンポーネントオーバーライドを一度定義 — すべてのMDXコンテンツにグローバルに適用。
export function useMDXComponents() {
return {
h1: (props) => (
<h1 className="text-4xl font-bold" {...props} />
),
code: ({ children, className }) => (
<SyntaxHighlighter language={className}>
{children}
</SyntaxHighlighter>
),
a: (props) => (
<Link className="text-blue-600" {...props} />
),
};
}
import { createServer, createTool }
from "@lazarv/react-server/mcp";
import { z } from "zod";
const search = createTool(
"search",
"Search the knowledge base",
{
query: z.string(),
limit: z.number().default(10),
},
async ({ query, limit }) => {
const results = await db.search(query, limit);
return results.map((r) => r.title).join("\n");
}
);
export default createServer({ tools: [search] });
AI統合
MCPサーバー
ツール、リソース、プロンプトをストリーミングHTTPエンドポイントとして提供するModel Context Protocolサーバーを構築。
Zodスキーマでツールを定義。AIエージェントが標準化されたプロトコルを通じてそれらを検出し呼び出します。各ツールはMCPクライアント互換のHTTPエンドポイントになります。
どこにでもデプロイ
本番ビルドはコマンド1つ。すべての主要プラットフォーム向けのビルトインアダプター — カスタムも可能。
アダプター
プラットフォームアダプター
Vercel、Netlify、Cloudflareに単一の設定オプションでデプロイ。各アダプターがプラットフォーム固有の出力 — エッジ関数、サーバーレス関数、Workers — を自動的に処理します。
カスタムが必要?アダプターコアパッケージの createAdapter で独自のアダプターを構築できます。アダプターAPIはビルド出力を完全に制御できます。
単一のコマンドでアプリをビルドし、プラットフォーム固有のデプロイ出力を生成。
react-server build --deploy
設定ファイルでアダプターを指定 — ビルドがエッジ関数、サーバーレス関数、Workersを自動的に出力。
{ "adapter": "vercel" }
またはCLI引数で直接アダプターを指定 — 設定ファイル不要。
react-server build --adapter vercel --deploy
ミドルウェアモードで既存のExpress、NestJS、またはconnect互換サーバーにランタイムを組み込み。
import { reactServer } from
"@lazarv/react-server/node";
const { middlewares } = await reactServer();
app.use(middlewares);
クラスターモードですべてのCPUコアに水平スケーリングし、最大スループットを実現。
REACT_SERVER_CLUSTER=8 react-server start
一貫した本番デプロイのために設定ファイルでクラスターサイズを構成。
{ "cluster": 8 }
ランタイム
マルチランタイム&本番環境
Node.js ≥ 20.10、Bun ≥ 1.2.9、またはDeno ≥ 2.0 で動作 — @lazarv/react-serverがランタイムを自動検出。ミドルウェアモードで既存のサーバーに組み込み可能。
クラスターモードですべてのCPUコアにスケール。静的エクスポートは動的ルートパラメータ、圧縮、キャッシュヘッダーを含む完全な静的サイトを生成。HTTPS、ソースマップ、gzip/brotli圧縮をビルトインで搭載。