fix(web): wrap useSearchParams in Suspense so next build can prerender
/servers/new and /login/callback call useSearchParams() directly, which bails the page out of static rendering and fails `next build` during prerender. Split each into a thin Suspense wrapper + inner component. Latent since `next dev` never prerenders — only surfaces in a prod build. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
38aa5875d3
commit
2b098c5d33
@ -1,6 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useEffect, useState } from 'react';
|
import { Suspense, useEffect, useState } from 'react';
|
||||||
import { useRouter, useSearchParams } from 'next/navigation';
|
import { useRouter, useSearchParams } from 'next/navigation';
|
||||||
import { apiFetch } from '@/lib/api';
|
import { apiFetch } from '@/lib/api';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
@ -82,7 +82,7 @@ function specToEditable(spec: PreviewResponse['spec']): EditableSpec {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function NewServerPage() {
|
function NewServerPageInner() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [step, setStep] = useState<Step>('prompt');
|
const [step, setStep] = useState<Step>('prompt');
|
||||||
|
|
||||||
@ -708,6 +708,26 @@ export default function NewServerPage() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// useSearchParams() forces client-side rendering — Next requires a Suspense
|
||||||
|
// boundary around it, or `next build` bails out of static generation.
|
||||||
|
export default function NewServerPage() {
|
||||||
|
return (
|
||||||
|
<Suspense
|
||||||
|
fallback={
|
||||||
|
<div className="mx-auto max-w-3xl px-6 py-8">
|
||||||
|
<h1 className="text-[22px] font-semibold tracking-tight">New MCP server</h1>
|
||||||
|
<div className="panel mt-10 p-8 text-center">
|
||||||
|
<Loader2 className="mx-auto animate-spin text-[--color-fg-muted]" size={20} />
|
||||||
|
<p className="mt-4 text-[13px] text-[--color-fg-muted]">Loading…</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<NewServerPageInner />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const SHARE_CATEGORIES = [
|
const SHARE_CATEGORIES = [
|
||||||
'productivity',
|
'productivity',
|
||||||
'developer-tools',
|
'developer-tools',
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useEffect, useState } from 'react';
|
import { Suspense, useEffect, useState } from 'react';
|
||||||
import { useRouter, useSearchParams } from 'next/navigation';
|
import { useRouter, useSearchParams } from 'next/navigation';
|
||||||
import { Logo } from '@/components/logo';
|
import { Logo } from '@/components/logo';
|
||||||
import { apiFetch } from '@/lib/api';
|
import { apiFetch } from '@/lib/api';
|
||||||
|
|
||||||
export default function CallbackPage() {
|
function CallbackInner() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const params = useSearchParams();
|
const params = useSearchParams();
|
||||||
const token = params.get('token');
|
const token = params.get('token');
|
||||||
@ -53,3 +53,19 @@ export default function CallbackPage() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// useSearchParams() requires a Suspense boundary or `next build` cannot
|
||||||
|
// statically render this route.
|
||||||
|
export default function CallbackPage() {
|
||||||
|
return (
|
||||||
|
<Suspense
|
||||||
|
fallback={
|
||||||
|
<div className="flex min-h-screen items-center justify-center px-6">
|
||||||
|
<p className="text-[13px] text-[--color-fg-muted]">Verifying your magic link…</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<CallbackInner />
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user