Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 25 additions & 7 deletions components/website/code-renderer.tsx
Original file line number Diff line number Diff line change
@@ -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<string | null>(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 (
<div className='font-mono'>
Expand Down
42 changes: 35 additions & 7 deletions lib/shiki.ts
Original file line number Diff line number Diff line change
@@ -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<Highlighter> => {
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<string> => {
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<void> => {
if (highlighter) {
highlighter.dispose();
highlighter = null; // Reset the cached instance
}
};