Skip to content

Commit 4eb64b4

Browse files
authored
fix: render GitHub stars server-side with revalidation cache (#40)
The stars count in the docs nav was fetched client-side from api.github.com on every visit, occasionally rendering "NaNk" when GitHub rate-limited the unauthenticated request. Move the fetch to the server layout using Next.js's data cache (revalidate: 3600) so the value is baked into the SSR'd HTML and only one upstream request is made per hour for the whole site. Add a typed stars prop on DocsLayout and a numeric fallback so the formatter can no longer produce NaN.
1 parent 3166ae0 commit 4eb64b4

4 files changed

Lines changed: 31 additions & 13 deletions

File tree

app/(home)/layout.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import type { ReactNode } from 'react';
22
import { baseOptions } from '@/app/layout.config';
33
import { DocsLayout } from '@/components/layouts/docs';
4+
import { getSteelBrowserStars } from '@/lib/github-stars';
45
import { source } from '@/lib/source';
56

6-
export default function Layout({ children }: { children: ReactNode }) {
7+
export default async function Layout({ children }: { children: ReactNode }) {
8+
const stars = await getSteelBrowserStars();
79
return (
8-
<DocsLayout {...baseOptions} tree={source.pageTree}>
10+
<DocsLayout {...baseOptions} tree={source.pageTree} stars={stars}>
911
{children}
1012
</DocsLayout>
1113
);

app/[...slug]/layout.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import type { ReactNode } from 'react';
22
import { baseOptions } from '@/app/layout.config';
33
import { DocsLayout } from '@/components/layouts/docs';
4+
import { getSteelBrowserStars } from '@/lib/github-stars';
45
import { source } from '@/lib/source';
56

6-
export default function Layout({ children }: { children: ReactNode }) {
7+
export default async function Layout({ children }: { children: ReactNode }) {
8+
const stars = await getSteelBrowserStars();
79
return (
8-
<DocsLayout {...baseOptions} tree={source.pageTree}>
10+
<DocsLayout {...baseOptions} tree={source.pageTree} stars={stars}>
911
{children}
1012
</DocsLayout>
1113
);

components/layouts/docs.tsx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,14 @@ import { renderNavItem } from './links';
2424
export interface DocsLayoutProps {
2525
tree: PageTree.Root;
2626
children: ReactNode;
27+
stars: number;
2728
}
2829

29-
export function DocsLayout({ tree, children }: DocsLayoutProps) {
30+
function formatStars(count: number): string {
31+
return `${(Math.round(count / 100) / 10).toFixed(1)}k`;
32+
}
33+
34+
export function DocsLayout({ tree, children, stars }: DocsLayoutProps) {
3035
const [isScrolled, setIsScrolled] = React.useState(false);
3136
// const { registerShortcut } = useKeyboardShortcuts();
3237
const { collapsed } = useSidebar();
@@ -43,7 +48,6 @@ export function DocsLayout({ tree, children }: DocsLayoutProps) {
4348
width: 0,
4449
visible: false,
4550
});
46-
const [stars, setStars] = React.useState<number>(5.5);
4751

4852
React.useEffect(() => {
4953
const handleScroll = () => {
@@ -82,12 +86,6 @@ export function DocsLayout({ tree, children }: DocsLayoutProps) {
8286
};
8387
}, [pathname, localizedLinks]);
8488

85-
React.useEffect(() => {
86-
fetch(`https://api.github.com/repos/steel-dev/steel-browser`)
87-
.then((res) => res.json())
88-
.then((data) => setStars((Math.round(data.stargazers_count / 100) * 100) / 1000));
89-
}, []);
90-
9189
return (
9290
<MobileMenuProvider>
9391
<TreeContextProvider tree={tree}>
@@ -145,7 +143,7 @@ export function DocsLayout({ tree, children }: DocsLayoutProps) {
145143
className="text-xs font-mono flex items-center gap-2 transition-colors"
146144
color="#A1A0A7"
147145
>
148-
<Github fill="#A1A0A7" width="16" /> {stars}k
146+
<Github fill="#A1A0A7" width="16" /> {formatStars(stars)}
149147
</Link>
150148
<div className="w-px h-6 bg-zinc-700"></div>
151149
{/*<CopyLLMSButton />*/}

lib/github-stars.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
const STEEL_BROWSER_REPO = 'steel-dev/steel-browser';
2+
const FALLBACK_STARS = 7000;
3+
const REVALIDATE_SECONDS = 3600;
4+
5+
export async function getSteelBrowserStars(): Promise<number> {
6+
try {
7+
const res = await fetch(`https://api.github.com/repos/${STEEL_BROWSER_REPO}`, {
8+
next: { revalidate: REVALIDATE_SECONDS },
9+
});
10+
if (!res.ok) return FALLBACK_STARS;
11+
const data = await res.json();
12+
return typeof data?.stargazers_count === 'number' ? data.stargazers_count : FALLBACK_STARS;
13+
} catch {
14+
return FALLBACK_STARS;
15+
}
16+
}

0 commit comments

Comments
 (0)