Skip to content

perf(web): Selective SSRとQuery hydrationを再設計 - #598

Merged
hmjn023 merged 1 commit into
developfrom
fix/issue-594-selective-ssr-query-hydration
Jul 13, 2026
Merged

perf(web): Selective SSRとQuery hydrationを再設計#598
hmjn023 merged 1 commit into
developfrom
fix/issue-594-selective-ssr-query-hydration

Conversation

@hmjn023

@hmjn023 hmjn023 commented Jul 12, 2026

Copy link
Copy Markdown
Owner

概要

Web主要routeのSelective SSRとSolid Query hydrationを再設計し、冷間F5の空本文・bootstrap race・hydrate後の重複fetchを解消します。

Fixes #594

変更内容

  • Sources / ConfigをFull data SSRへ移行
  • Search / Manager / Source Media / Media Detailをroute固有static fallback + Query preload/hydrationへ移行
  • server bootstrapをloaderより前に完了し、server QueryClientをrequest単位、browserをsingleton化
  • Solid Router SSR Query integrationでdehydrate/hydrateを統合
  • Search session復元完了までprimary queryをgateし、intent hoverによるstore変更と二重取得を防止
  • server / Tauriで共有するinfinite query option builderを追加
  • raw SSR、直接URL、F5、SPA intent、cache再訪、API request数、表示時間budgetのE2Eを追加
  • Full SSR後の操作可能性とSSE更新後のdialog/input/focus保持を回帰検証
  • route分類、baseline、budget、data-only不採用理由を設計文書化

技術詳細

  • 現行Solid Routerのdata-only SSRはhydration key mismatchを再現したため採用せず、server/clientで同じcomponent treeを使うssr: trueを選択しました
  • 初回hydration完了をhtmlのdata-hydrated属性で明示し、SSR DOM可視とinteraction readyを区別します
  • session依存のmedia.searchはserver loaderから除外し、復元後条件でcold load/reload各1回だけ実行します
  • SourcesのFull SSRはdehydrated JSON内の文字列ではなくsource-card実DOMも検証します

テスト

  • dev E2E: 24 passed
  • fresh production build E2E: 24 passed
  • server unit: 162 passed
  • server integration: 67 passed
  • UI: 40 passed
  • core: 14 passed
  • CLI: 11 passed
  • 全workspace typecheck: passed
  • 変更ファイルのBiome check / Vite+ lint: passed(既存warningのみ)

補足

monorepo全体のvp checkは変更外を含む既存ファイル多数がOxfmt未適用のためformat段階で失敗します。変更ファイルは既存のBiome規約でformat/check済みです。導入済みVite+ 0.1.24にはAGENTS記載のvp env doctorサブコマンドがありません。

Summary by CodeRabbit

  • 新機能

    • 主要画面でサーバー側データ取得に対応し、直接アクセスや再読み込み時にも内容を早く表示できるようになりました。
    • 検索条件をセッションに保存・復元し、復元完了後に検索結果を表示するようになりました。
    • 設定、検索、ソース画面などに分かりやすい読み込み中表示を追加しました。
    • ソースカードからの画面遷移が改善されました。
  • バグ修正

    • 配列を含む検索条件の比較精度を改善しました。
    • SSR後の重複通信や画面遷移時の表示不整合を抑制しました。
  • テスト

    • 直接アクセス、再読み込み、遅延通信、検索状態復元の検証を強化しました。

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

主要ルートをSSR対応にし、loaderによるQuery preloadとhydration統合を追加しました。検索状態のセッション復元、検索クエリ生成、pending表示、SSR・SPA遷移のE2E検証、関連ドキュメントとユーティリティテストも更新しています。

Changes

SSR・Query hydration と検索状態復元

Layer / File(s) Summary
遅延ルーター初期化とSSR Query統合
apps/server/src/router.tsx
サーバー依存関係を遅延初期化し、非同期ルーター生成後にSSR Query統合を設定するよう変更しました。
主要ルートのSSR loaderとpending表示
apps/server/src/routes/*, packages/ui/src/router-status.tsx, packages/ui/src/source-card.tsx
Config、Manager、Search、Sources、Source Media、Media DetailをSSR化し、loader、pending表示、mount後描画、ルート遷移を追加しました。
検索クエリとセッション状態の統合
packages/ui/src/hooks/*, packages/ui/src/query-options/*, packages/ui/src/preset-manager.tsx, packages/core/src/utils/deep-equal.ts
検索結果クエリの共通ビルダー、セッション状態の復元完了制御、プリセット照合、配列対応のdeepEqualを追加しました。
SSR・hydrationのE2E検証基盤
apps/server/src/tests/e2e/*
SSR本文、hydration完了、APIリクエスト数、ナビゲーション予算、遅延遷移、リロード回復を検証するテストと計測基盤を更新しました。
SSR運用方針と検証補助
docs/design/web-rendering-strategy.md
ルート方式、Query hydration、sessionStorage復元、リクエスト予算、E2E検証条件を文書化しました。

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related issues

  • Issue 576: サーバールーター、loader、SSR・CSR境界、Query hydrationを通じて初期表示と重複リクエストを扱っています。
  • Issue 578: loaderとQuery状態モデルの統合、および検索クエリ実行条件の変更が関連します。
  • Issue 577: ルーター、ルートpending表示、hydration対応のアプリシェル変更が関連します。

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.45% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed タイトルはSelective SSRとQuery hydrationの再設計という主要変更を簡潔に表しています。
Linked Issues check ✅ Passed #594の要件であるSSR/CSR境界の再設計、bootstrap完了待ち、Query hydration、E2E検証と文書化が実装されています。
Out of Scope Changes check ✅ Passed 追加変更は目的に沿った支援実装や検証・文書化に収まっており、明確な無関係変更は見当たりません。
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-594-selective-ssr-query-hydration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/server/src/routes/sources/index.tsx (1)

47-78: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

statesourceData() ベースにする
loaderData().mediaSources がある間も、state は生のクエリだけを見ているため、カード一覧と「読み込み中 / エラー」が同時に出る。config.tsx と同じように、sourceData() === undefined を条件にするか、state もマージ済みデータで組み立ててください。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/server/src/routes/sources/index.tsx` around lines 47 - 78, Update the
state callback in SourcesRouteContent to use the merged sourceData() value
rather than raw mediaSources query data, so loader-provided media sources do not
display alongside loading or error states. Make the loading/error condition
depend on whether sourceData() is undefined, while preserving the existing
empty-list handling.
🧹 Nitpick comments (1)
apps/server/src/routes/sources/$mediaSourceId/index.tsx (1)

38-50: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

SourceMediaRoute の isMounted ゲートが SourceMediaPage 側と二重になっている

./components/source-media-page.tsxSourceMediaPage は既に自前の createSignal/onMount/Show によるマウント待機とフォールバック表示を実装しています。ここで再度同じパターンで外側にゲートを追加すると、ハイドレーション後に2段階のマウント待ちが発生し、実コンテンツ表示までに不要な1ティック分の遅延が増えます。本PRが目標とする表示時間短縮と方向性が逆です。外側のゲートを外し、SourceMediaPage 自身のゲート処理に委ねることを検討してください。

♻️ 簡略化案
 function SourceMediaRoute() {
-	const [isMounted, setIsMounted] = createSignal(false);
-
-	onMount(() => {
-		setIsMounted(true);
-	});
-
-	return (
-		<Show fallback={<SourceMediaRouteFallback />} when={isMounted()}>
-			{(_mounted) => <SourceMediaPage />}
-		</Show>
-	);
+	return <SourceMediaPage />;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/server/src/routes/sources/`$mediaSourceId/index.tsx around lines 38 -
50, Remove the redundant isMounted signal, onMount callback, and outer Show gate
from SourceMediaRoute, and render SourceMediaPage directly so its existing mount
handling and fallback remain solely responsible for hydration readiness.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@apps/server/src/routes/sources/index.tsx`:
- Around line 47-78: Update the state callback in SourcesRouteContent to use the
merged sourceData() value rather than raw mediaSources query data, so
loader-provided media sources do not display alongside loading or error states.
Make the loading/error condition depend on whether sourceData() is undefined,
while preserving the existing empty-list handling.

---

Nitpick comments:
In `@apps/server/src/routes/sources/`$mediaSourceId/index.tsx:
- Around line 38-50: Remove the redundant isMounted signal, onMount callback,
and outer Show gate from SourceMediaRoute, and render SourceMediaPage directly
so its existing mount handling and fallback remain solely responsible for
hydration readiness.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 220b88bc-8913-4bd6-bbc5-a00e29a1976b

📥 Commits

Reviewing files that changed from the base of the PR and between 0a4e07b and a73da00.

📒 Files selected for processing (29)
  • apps/server/src/router.tsx
  • apps/server/src/routes/__root.tsx
  • apps/server/src/routes/config.tsx
  • apps/server/src/routes/manager.tsx
  • apps/server/src/routes/search.tsx
  • apps/server/src/routes/sources/$mediaSourceId/$mediaId/index.tsx
  • apps/server/src/routes/sources/$mediaSourceId/index.tsx
  • apps/server/src/routes/sources/index.tsx
  • apps/server/src/tests/e2e/loading-recovery.spec.ts
  • apps/server/src/tests/e2e/realtime-preservation.spec.ts
  • apps/server/src/tests/e2e/route-reload.spec.ts
  • apps/server/src/tests/e2e/support/test.ts
  • apps/tauri/src/hooks/use-current-search-persistence.ts
  • apps/tauri/src/routes/search.tsx
  • docs/design/web-rendering-strategy.md
  • packages/core/src/utils/deep-equal.ts
  • packages/core/tests/deep-equal.test.ts
  • packages/ui/src/hooks/use-current-search-persistence.test.ts
  • packages/ui/src/hooks/use-current-search-persistence.ts
  • packages/ui/src/hooks/use-search-page.ts
  • packages/ui/src/hooks/use-source-media-page.ts
  • packages/ui/src/preset-manager.tsx
  • packages/ui/src/query-options/index.ts
  • packages/ui/src/query-options/search-query.test.ts
  • packages/ui/src/query-options/search-query.ts
  • packages/ui/src/router-status.tsx
  • packages/ui/src/screens/source-media-screen.tsx
  • packages/ui/src/source-card.tsx
  • packages/ui/src/source-media-page.tsx
💤 Files with no reviewable changes (1)
  • packages/ui/src/screens/source-media-screen.tsx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant