Core & UI: hotfix <DynamicCodeBlock /> Vite + React 19.2 compat issues

This commit is contained in:
Fuma Nama
2025-10-22 13:36:55 +08:00
parent 693fef4e94
commit 45f0c1fc62
3 changed files with 31 additions and 16 deletions
+6
View File
@@ -0,0 +1,6 @@
---
'fumadocs-core': patch
'fumadocs-ui': patch
---
hotfix `<DynamicCodeBlock />` Vite + React 19.2 compat issues
+8 -12
View File
@@ -1,26 +1,22 @@
'use client';
import {
type DependencyList,
type ReactNode,
use,
useId,
useMemo,
} from 'react';
import { type DependencyList, type ReactNode, use, useMemo } from 'react';
import { highlight, type HighlightOptions } from './shiki';
const promises: Record<string, Promise<ReactNode>> = {};
/**
* get highlighted results, should be used with React Suspense API.
*
* note: results are cached with (lang, code) as keys, if this is not the desired behaviour, pass a `deps` instead.
*/
export function useShiki(
code: string,
options: HighlightOptions,
deps?: DependencyList,
): ReactNode {
const id = useId();
const key = useMemo(() => {
const state = deps ? JSON.stringify(deps) : `${options.lang}:${code}`;
return `${id}:${state}`;
}, [code, deps, id, options.lang]);
return deps ? JSON.stringify(deps) : `${options.lang}:${code}`;
}, [code, deps, options.lang]);
return use((promises[key] ??= highlight(code, options)));
}
@@ -13,6 +13,8 @@ import {
type FC,
Suspense,
use,
useDeferredValue,
useId,
} from 'react';
export interface DynamicCodeblockProps {
@@ -56,6 +58,7 @@ export function DynamicCodeBlock({
options,
wrapInSuspense = true,
}: DynamicCodeblockProps) {
const id = useId();
const shikiOptions = {
lang,
...options,
@@ -64,10 +67,18 @@ export function DynamicCodeBlock({
...options?.components,
},
} satisfies HighlightOptions;
let children = <Internal code={code} options={shikiOptions} />;
const children = (
<PropsContext value={codeblock}>
<Internal
id={id}
{...useDeferredValue({ code, options: shikiOptions })}
/>
</PropsContext>
);
if (wrapInSuspense)
children = (
return (
<Suspense
fallback={
<Placeholder code={code} components={shikiOptions.components} />
@@ -77,7 +88,7 @@ export function DynamicCodeBlock({
</Suspense>
);
return <PropsContext value={codeblock}>{children}</PropsContext>;
return children;
}
function Placeholder({
@@ -106,11 +117,13 @@ function Placeholder({
}
function Internal({
id,
code,
options,
}: {
id: string;
code: string;
options: HighlightOptions;
}) {
return useShiki(code, options);
return useShiki(code, options, [id, options.lang, code]);
}