Web Components SSR Framework

統一的なコンポーネント定義からSSRとHydrationを行うフレームワーク

Counter (SSR済み)

サーバーで renderToString(Counter, { count: 10 }) を実行した想定

TODO List (SSR済み)

サーバーで初期アイテム付きでレンダリング

Counter (CSR - 比較用)

SSRなしでJavaScriptのみでレンダリング

フレームワーク設計

// 1. コンポーネント定義 (共通)
const Counter = defineComponent({
  name: 'my-counter',
  styles: `...`,
  initialState: { count: 0 },
  render(state) {
    return `<div>Count: ${state.count}</div>...`;
  },
  handlers: {
    increment: (state) => ({ count: state.count + 1 }),
  },
});

// 2. サーバーサイド (Node.js)
const html = renderToString(Counter, { count: 10 });

// 3. クライアントサイド (Browser)
registerComponent(Counter);  // Hydration

処理フロー

┌─────────────────────────────────────────────────────┐
│ Server                                              │
│                                                     │
│  Component Def ──► renderToString() ──► HTML        │
│       │                                    │        │
│       │            ┌──────────────────────┐│        │
│       │            │ <my-counter>        ││        │
│       │            │   <template>...     ││        │
│       │            │   data-state="..."  ││        │
│       │            │ </my-counter>       ││        │
│       │            └──────────────────────┘│        │
└───────┼────────────────────────────────────┼────────┘
        │                                    │
        │              HTTP Response         │
        │                                    ▼
┌───────┼────────────────────────────────────┬────────┐
│ Browser                                    │        │
│       │                                    │        │
│       │  HTML Parse ──► Declarative Shadow DOM      │
│       │                 (即座に表示)                │
│       │                                    │        │
│       ▼                                    │        │
│  registerComponent() ──► customElements.define()    │
│       │                                              │
│       │  connectedCallback()                        │
│       │    ├── shadowRoot exists? ──► Hydrate       │
│       │    │   └── attachEventListeners()           │
│       │    └── no shadowRoot ──► CSR Render         │
│       │                                              │
│       ▼                                              │
│  Interactive Component                              │
└─────────────────────────────────────────────────────┘

Hydration状態

JavaScript読み込み前...