Skip to content

Commit c8aeae6

Browse files
authored
chore: load katex with async stylesheet (#4680)
1 parent c4b9c65 commit c8aeae6

File tree

2 files changed

+43
-14
lines changed

2 files changed

+43
-14
lines changed

packages/fern-docs/bundle/src/app/layout.tsx

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { Providers } from "@fern-docs/components/providers/providers";
66
import type { Metadata, Viewport } from "next/types";
77
import { experimental_taintUniqueValue } from "react";
88

9+
import { AsyncStylesheet } from "@/components/AsyncStylesheet";
910
import { ConsoleMessage } from "@/components/console-message";
1011
import { WebSocketRefresh } from "@/components/websocket-refresh";
1112

@@ -56,23 +57,10 @@ export default function Layout({ children }: { children: React.ReactNode }) {
5657
<link rel="dns-prefetch" href="https://cdn.jsdelivr.net" />
5758

5859
{/* Non-blocking KaTeX CSS loading */}
59-
<link
60-
rel="preload"
61-
as="style"
60+
<AsyncStylesheet
6261
href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css"
6362
crossOrigin="anonymous"
6463
/>
65-
<link
66-
rel="stylesheet"
67-
href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css"
68-
media="print"
69-
onload="this.media='all'"
70-
/>
71-
<noscript
72-
dangerouslySetInnerHTML={{
73-
__html: '<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css" />'
74-
}}
75-
/>
7664
</head>
7765
);
7866

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"use client";
2+
3+
/**
4+
* AsyncStylesheet - Non-blocking CSS loading component
5+
*
6+
* Loads a stylesheet asynchronously without blocking page render.
7+
* Uses the media="print" + onLoad trick for optimal performance while
8+
* maintaining React/TypeScript compatibility.
9+
*/
10+
11+
interface AsyncStylesheetProps {
12+
href: string;
13+
crossOrigin?: "anonymous" | "use-credentials";
14+
}
15+
16+
export function AsyncStylesheet({ href, crossOrigin = "anonymous" }: AsyncStylesheetProps) {
17+
return (
18+
<>
19+
{/* Preload hint for early resource discovery */}
20+
<link rel="preload" as="style" href={href} crossOrigin={crossOrigin} />
21+
22+
{/* Async loading with media swap trick - React's onLoad works here */}
23+
<link
24+
rel="stylesheet"
25+
href={href}
26+
media="print"
27+
crossOrigin={crossOrigin}
28+
onLoad={(e) => {
29+
(e.target as HTMLLinkElement).media = "all";
30+
}}
31+
/>
32+
33+
{/* Fallback for users with JavaScript disabled */}
34+
<noscript
35+
dangerouslySetInnerHTML={{
36+
__html: `<link rel="stylesheet" href="${href}" crossorigin="${crossOrigin}" />`
37+
}}
38+
/>
39+
</>
40+
);
41+
}

0 commit comments

Comments
 (0)