fix(frontend): marketplace page load and caching (#10934)

## Changes 🏗️

### **Server-Side:**
-  **ISR Cache**: Page cached for 60 seconds, served instantly
-  **Prefetch**: All API calls made on server, not client
-  **Static Generation**: HTML pre-rendered with data
-  **Streaming**: Loading states show immediately

### **Client-Side:**
-  **No API Calls**: Data hydrated from server cache
-  **Fast Hydration**: React Query uses prefetched data
-  **Smart Caching**: 60s stale time prevents unnecessary requests
-  **Progressive Loading**: Suspense boundaries for better UX

### **🔄 Caching Strategy:**

1. **Server**: ISR cache (60s) → API calls → Static HTML
2. **CDN**: Cached HTML served instantly
3. **Client**: Hydrated data from server → No additional API calls
4. **Background**: ISR regenerates stale pages automatically

### **🎯 Result:**
- **First Visit**: Instant HTML + hydrated data (no client API calls)
- **Subsequent Visits**: Instant cached page
- **Background Updates**: Automatic revalidation every 60s
- **Optimal Performance**: Server-side rendering + client-side caching

## Checklist 📋

### For code changes:
- [x] I have clearly listed my changes in the PR description
- [x] I have made a test plan
- [x] I have tested my changes according to the test plan:
  - [x] Run the app locally
  - [x] Marketplace page loads are faster 

### For configuration changes:

None
This commit is contained in:
Ubbe
2025-09-17 16:23:43 +09:00
committed by GitHub
parent dd84fb5c66
commit 6d6bf308fc
3 changed files with 52 additions and 14 deletions

View File

@@ -5,8 +5,15 @@ import {
import { StoreAgentsResponse } from "@/app/api/__generated__/models/storeAgentsResponse";
import { CreatorsResponse } from "@/app/api/__generated__/models/creatorsResponse";
const queryConfig = {
staleTime: 60 * 1000, // 60 seconds - match server cache
gcTime: 5 * 60 * 1000, // 5 minutes
refetchOnWindowFocus: false, // Avoid unnecessary refetches
refetchOnMount: false, // Use cached data from server
};
export const useMainMarketplacePage = () => {
// Below queries are already fetched on server and hydrated properly in cache, hence these requests are fast
// Data is prefetched on server and hydrated, these queries will use cached data
const {
data: featuredAgents,
isLoading: isFeaturedAgentsLoading,
@@ -15,6 +22,7 @@ export const useMainMarketplacePage = () => {
{ featured: true },
{
query: {
...queryConfig,
select: (x) => {
return x.data as StoreAgentsResponse;
},
@@ -33,6 +41,7 @@ export const useMainMarketplacePage = () => {
},
{
query: {
...queryConfig,
select: (x) => {
return x.data as StoreAgentsResponse;
},
@@ -48,6 +57,7 @@ export const useMainMarketplacePage = () => {
{ featured: true, sorted_by: "num_agents" },
{
query: {
...queryConfig,
select: (x) => {
return x.data as CreatorsResponse;
},

View File

@@ -0,0 +1,5 @@
import { MainMarketplacePageLoading } from "./components/MainMarketplacePageLoading";
export default function Loading() {
return <MainMarketplacePageLoading />;
}

View File

@@ -1,4 +1,5 @@
import { Metadata } from "next";
import { Suspense } from "react";
import {
prefetchGetV2ListStoreAgentsQuery,
prefetchGetV2ListStoreCreatorsQuery,
@@ -6,8 +7,7 @@ import {
import { getQueryClient } from "@/lib/react-query/queryClient";
import { dehydrate, HydrationBoundary } from "@tanstack/react-query";
import { MainMarkeplacePage } from "./components/MainMarketplacePage/MainMarketplacePage";
export const dynamic = "force-dynamic";
import { MainMarketplacePageLoading } from "./components/MainMarketplacePageLoading";
// FIX: Correct metadata
export const metadata: Metadata = {
@@ -56,22 +56,45 @@ export const metadata: Metadata = {
export default async function MarketplacePage(): Promise<React.ReactElement> {
const queryClient = getQueryClient();
// Prefetch all data on server with proper caching
await Promise.all([
prefetchGetV2ListStoreAgentsQuery(queryClient, {
featured: true,
}),
prefetchGetV2ListStoreAgentsQuery(queryClient, {
sorted_by: "runs",
}),
prefetchGetV2ListStoreCreatorsQuery(queryClient, {
featured: true,
sorted_by: "num_agents",
}),
prefetchGetV2ListStoreAgentsQuery(
queryClient,
{ featured: true },
{
query: {
staleTime: 60 * 1000, // 60 seconds
gcTime: 5 * 60 * 1000, // 5 minutes (formerly cacheTime)
},
},
),
prefetchGetV2ListStoreAgentsQuery(
queryClient,
{ sorted_by: "runs", page_size: 1000 },
{
query: {
staleTime: 60 * 1000, // 60 seconds
gcTime: 5 * 60 * 1000, // 5 minutes
},
},
),
prefetchGetV2ListStoreCreatorsQuery(
queryClient,
{ featured: true, sorted_by: "num_agents" },
{
query: {
staleTime: 60 * 1000, // 60 seconds
gcTime: 5 * 60 * 1000, // 5 minutes
},
},
),
]);
return (
<HydrationBoundary state={dehydrate(queryClient)}>
<MainMarkeplacePage />
<Suspense fallback={<MainMarketplacePageLoading />}>
<MainMarkeplacePage />
</Suspense>
</HydrationBoundary>
);
}