diff --git a/components/website/code-renderer.tsx b/components/website/code-renderer.tsx index 04242ce8..8b79e1f6 100644 --- a/components/website/code-renderer.tsx +++ b/components/website/code-renderer.tsx @@ -1,15 +1,33 @@ -import { codeToHtml } from '@/lib/shiki'; +'use client'; +import { useEffect, useState } from 'react'; +import { codeToHtml, disposeHighlighter } from '@/lib/shiki'; -type CodeRenderer = { +type CodeRendererProps = { code: string; lang: string; }; -export default async function CodeRenderer({ code, lang }: CodeRenderer) { - const html = await codeToHtml({ - code, - lang, - }); +export default function CodeRenderer({ code, lang }: CodeRendererProps) { + const [html, setHtml] = useState(null); + + useEffect(() => { + const fetchHtml = async () => { + try { + const generatedHtml = await codeToHtml({ code, lang }); + setHtml(generatedHtml); + } catch (error) { + console.error('Error generating HTML:', error); + } + }; + + fetchHtml(); + + return () => { + // Avoid disposing if the highlighter might still be needed + // Consider removing or commenting out this line if it's causing issues + // disposeHighlighter(); + }; + }, [code, lang]); return (
diff --git a/lib/shiki.ts b/lib/shiki.ts index 98075a8a..a87fb3ed 100644 --- a/lib/shiki.ts +++ b/lib/shiki.ts @@ -1,20 +1,48 @@ -import { bundledLanguages, createHighlighter } from 'shiki/bundle/web'; +import { + bundledLanguages, + createHighlighter, + Highlighter, +} from 'shiki/bundle/web'; import { noir } from './custom-theme'; +// This variable will hold the cached highlighter instance +let highlighter: Highlighter | null = null; + +const getHighlighter = async (): Promise => { + if (!highlighter) { + // Create it only once + highlighter = await createHighlighter({ + themes: [noir], + langs: [...Object.keys(bundledLanguages)], + }); + } + return highlighter; +}; + export const codeToHtml = async ({ code, lang, }: { code: string; lang: string; -}) => { - const highlighter = await createHighlighter({ - themes: [noir], - langs: [...Object.keys(bundledLanguages)], - }); +}): Promise => { + const highlighterInstance = await getHighlighter(); - return highlighter.codeToHtml(code, { + // Ensure highlighterInstance is not null + if (!highlighterInstance) { + throw new Error('Highlighter instance is null'); + } + + return highlighterInstance.codeToHtml(code, { lang: lang, theme: 'noir', }); }; + +// Function to dispose of the highlighter when done (e.g., server-side cleanup) +export const disposeHighlighter = async (): Promise => { + if (highlighter) { + highlighter.dispose(); + highlighter = null; // Reset the cached instance + } +};