diff --git a/src/lib/docs-content/remark-code-blocks.js b/src/lib/docs-content/remark-code-blocks.js index 09e9edc..dcefdb6 100644 --- a/src/lib/docs-content/remark-code-blocks.js +++ b/src/lib/docs-content/remark-code-blocks.js @@ -1,34 +1,52 @@ // @ts-check -import { createHighlighter, createCssVariablesTheme } from 'shiki'; -import { visit } from 'unist-util-visit'; +import { createHighlighter, createCssVariablesTheme } from "shiki"; +import { visit } from "unist-util-visit"; -const cssVarsTheme = createCssVariablesTheme({ name: 'css-variables', variablePrefix: '--shiki-', fontStyle: true }); +const cssVarsTheme = createCssVariablesTheme({ + name: "css-variables", + variablePrefix: "--shiki-", + fontStyle: true, +}); -/** @type {import('shiki').Highlighter | undefined} */ -let hl; +// 1. Cast globalThis to include your custom property type +/** @type {any} */ +const globalObj = globalThis; -async function getHighlighter() { - if (!hl) { - hl = await createHighlighter({ - themes: [cssVarsTheme], - langs: [ - 'bash', 'sh', 'shell', - 'json', 'jsonc', 'yaml', 'toml', - 'typescript', 'javascript', 'jsx', 'tsx', - 'svelte', - 'markdown', - 'rust', 'go', - 'sql', - 'python', - 'html', 'css', - 'diff', - 'text' - ] - }); - } - return hl; +if (!globalObj._shikiHighlighterPromise) { + globalObj._shikiHighlighterPromise = createHighlighter({ + themes: [cssVarsTheme], + langs: [ + "bash", + "sh", + "shell", + "json", + "jsonc", + "yaml", + "toml", + "typescript", + "javascript", + "jsx", + "tsx", + "svelte", + "markdown", + "rust", + "go", + "sql", + "python", + "html", + "css", + "diff", + "text", + ], + }); } +/** + * Extract the promise for easier type annotation + * @type {Promise} + */ +const highlighterPromise = globalObj._shikiHighlighterPromise; + /** * Converts fenced code blocks to component tags with Shiki-highlighted * HTML pre-rendered at build time using the css-variables theme. @@ -37,41 +55,44 @@ async function getHighlighter() { */ export function remarkCodeBlocks() { return async (tree) => { - const highlighter = await getHighlighter(); + const highlighter = await highlighterPromise; const supported = new Set(highlighter.getLoadedLanguages()); - visit(tree, 'code', (node, index, parent) => { + visit(tree, "code", (node, index, parent) => { if (!parent || index === undefined) return; - const lang = node.lang ?? ''; - const fileMatch = /file="([^"]+)"/.exec(node.meta ?? ''); - const file = fileMatch?.[1] ?? ''; + const lang = node.lang ?? ""; + const fileMatch = /file="([^"]+)"/.exec(node.meta ?? ""); + const file = fileMatch?.[1] ?? ""; const code = JSON.stringify(node.value); - const resolvedLang = lang && supported.has(lang) ? lang : 'text'; + const resolvedLang = lang && supported.has(lang) ? lang : "text"; let highlighted; try { highlighted = highlighter.codeToHtml(node.value, { lang: resolvedLang, - theme: 'css-variables' + theme: "css-variables", }); } catch { - highlighted = highlighter.codeToHtml(node.value, { lang: 'text', theme: 'css-variables' }); + highlighted = highlighter.codeToHtml(node.value, { + lang: "text", + theme: "css-variables", + }); } const props = [ `code={${code}}`, `highlighted={${JSON.stringify(highlighted)}}`, lang && `lang="${lang}"`, - file && `file="${file}"` + file && `file="${file}"`, ] .filter(Boolean) - .join(' '); + .join(" "); /** @type {any} */ (parent.children)[index] = { - type: 'html', - value: `` + type: "html", + value: ``, }; }); };