perf(workspace): server-prefetch home, knowledge, tables, and files list pages#5196
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryLow Risk Overview Each page is now an async RSC that reads Shared Reviewed by Cursor Bugbot for commit f0881cc. Configure here. |
|
@greptile review |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 4b6eabb. Configure here.
Greptile SummaryThis PR extends the existing server-prefetch pattern to four more workspace list pages (home, knowledge, tables, and files), eliminating the flash of empty content that previously occurred because those routes fetched data on mount rather than at the server render boundary.
Confidence Score: 5/5Safe to merge — the change is purely additive, server-prefetch failures are silently absorbed so no page is broken if a prefetch call fails, and client components are left untouched. All four prefetch functions use the existing getQueryClient-per-request pattern, correctly await before dehydrate(), and match query keys and stale-times against their client hooks. The two observations are minor style inconsistencies with no user-visible impact. No files require special attention. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Browser
participant RSC as Server Component (Page)
participant PF as prefetch*.ts
participant API as Internal API Route
participant QC as QueryClient
participant HB as HydrationBoundary
participant CC as Client Component
Browser->>RSC: GET /workspace/[id]/home (etc.)
RSC->>PF: prefetchHomeLists(queryClient, workspaceId)
RSC->>RSC: getSession() [runs concurrently]
PF->>API: GET /api/folders?... (cookie forwarded)
PF->>API: GET /api/workspaces/.../files?... (cookie forwarded)
API-->>PF: JSON responses
PF->>QC: prefetchQuery → cache primed
RSC->>RSC: dehydrate(queryClient)
RSC->>HB: render with dehydrated state
HB->>CC: hydrate with pre-filled cache
CC-->>Browser: First paint with data (no loading flash)
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Browser
participant RSC as Server Component (Page)
participant PF as prefetch*.ts
participant API as Internal API Route
participant QC as QueryClient
participant HB as HydrationBoundary
participant CC as Client Component
Browser->>RSC: GET /workspace/[id]/home (etc.)
RSC->>PF: prefetchHomeLists(queryClient, workspaceId)
RSC->>RSC: getSession() [runs concurrently]
PF->>API: GET /api/folders?... (cookie forwarded)
PF->>API: GET /api/workspaces/.../files?... (cookie forwarded)
API-->>PF: JSON responses
PF->>QC: prefetchQuery → cache primed
RSC->>RSC: dehydrate(queryClient)
RSC->>HB: render with dehydrated state
HB->>CC: hydrate with pre-filled cache
CC-->>Browser: First paint with data (no loading flash)
Reviews (3): Last reviewed commit: "perf(workspace): server-prefetch home, k..." | Re-trigger Greptile |
Greptile SummaryThis PR extends the existing server-side prefetch +
Confidence Score: 4/5Safe to merge — the change is purely additive, existing client components are untouched, and pages fall back gracefully to a client refetch on any server prefetch failure. The implementation is well-aligned with the established prefetch pattern in the codebase and query-key alignment is verified by tests importing real factory functions. The one non-trivial logic gap is in files/prefetch.ts: the file-folders queryFn returns data.folders without a null fallback, while the adjacent files queryFn defensively falls back to [] — an inconsistency that could leave undefined in the cache under unexpected API responses. The graceful-failure test suite also only exercises one of the four prefetch functions. apps/sim/app/workspace/[workspaceId]/files/prefetch.ts — the folder queryFn missing null-fallback is the only concrete improvement needed; all other files look correct. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Browser
participant NextRSC as Next.js RSC (Server)
participant InternalAPI as Internal /api routes
participant QueryClient as TanStack QueryClient
participant HB as HydrationBoundary
participant ClientHook as Client useXxx hooks
Browser->>NextRSC: GET /workspace/[id]/home (or knowledge/tables/files)
activate NextRSC
NextRSC->>QueryClient: getQueryClient() — new per-request instance
par Parallel prefetch
NextRSC->>InternalAPI: "GET /api/folders?workspaceId=…&scope=active (cookie forwarded)"
InternalAPI-->>NextRSC: "{ folders: [...] }"
NextRSC->>QueryClient: prefetchQuery(folderKeys.list, mapFolder(rows))
and
NextRSC->>InternalAPI: "GET /api/workspaces/…/files?scope=active"
InternalAPI-->>NextRSC: "{ success, files: [...] }"
NextRSC->>QueryClient: prefetchQuery(workspaceFilesKeys.list, files)
end
NextRSC->>QueryClient: dehydrate(queryClient)
NextRSC->>Browser: SSR HTML + dehydrated state prop to HydrationBoundary
deactivate NextRSC
Browser->>HB: React hydration — restore dehydrated queries into client QueryClient
activate HB
HB->>ClientHook: queries already cached and fresh within staleTime
deactivate HB
Note over ClientHook,Browser: First paint shows populated lists — no skeleton flash
ClientHook-->>Browser: renders data immediately
Note over ClientHook: After staleTime (30–60 s), hooks refetch normally
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Browser
participant NextRSC as Next.js RSC (Server)
participant InternalAPI as Internal /api routes
participant QueryClient as TanStack QueryClient
participant HB as HydrationBoundary
participant ClientHook as Client useXxx hooks
Browser->>NextRSC: GET /workspace/[id]/home (or knowledge/tables/files)
activate NextRSC
NextRSC->>QueryClient: getQueryClient() — new per-request instance
par Parallel prefetch
NextRSC->>InternalAPI: "GET /api/folders?workspaceId=…&scope=active (cookie forwarded)"
InternalAPI-->>NextRSC: "{ folders: [...] }"
NextRSC->>QueryClient: prefetchQuery(folderKeys.list, mapFolder(rows))
and
NextRSC->>InternalAPI: "GET /api/workspaces/…/files?scope=active"
InternalAPI-->>NextRSC: "{ success, files: [...] }"
NextRSC->>QueryClient: prefetchQuery(workspaceFilesKeys.list, files)
end
NextRSC->>QueryClient: dehydrate(queryClient)
NextRSC->>Browser: SSR HTML + dehydrated state prop to HydrationBoundary
deactivate NextRSC
Browser->>HB: React hydration — restore dehydrated queries into client QueryClient
activate HB
HB->>ClientHook: queries already cached and fresh within staleTime
deactivate HB
Note over ClientHook,Browser: First paint shows populated lists — no skeleton flash
ClientHook-->>Browser: renders data immediately
Note over ClientHook: After staleTime (30–60 s), hooks refetch normally
Reviews (2): Last reviewed commit: "perf(workspace): server-prefetch home, k..." | Re-trigger Greptile |
4b6eabb to
f0881cc
Compare
|
@greptile review |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit f0881cc. Configure here.
Summary
<HydrationBoundary>to the home, knowledge, tables, and files workspace list pages (previously only 2 of ~24 routes prefetched; the rest fetched on mount after hydration).dehydrate()so the client hydrates with resolved data (the app has noReactQueryStreamedHydration, so pending-query dehydration would be unreliable).prefetch-internal-fetch.tshelper centralizes the cookie-forwarded internal-route GET; payloads withDatefields go through the/apiroute to match the client wire shape.Type of Change
Testing
prefetch.test.ts: 6 tests assert each prefetch primes the EXACTqueryKeyits client hook reads (imported from the real key factories, so hydration can't silently drift) + graceful-failure-no-throw + folder Date mapping.useFolders/useWorkspaceFiles/useWorkspaceFileFolders/useKnowledgeBasesList/useTablesList.tsc0 errors,check:react-query+check:api-validationpass, Biome clean.Checklist