diff --git a/src/components/modules/shared/CodeBlock.tsx b/src/components/modules/shared/CodeBlock.tsx index 34d1c150556..145fa687774 100644 --- a/src/components/modules/shared/CodeBlock.tsx +++ b/src/components/modules/shared/CodeBlock.tsx @@ -3,6 +3,7 @@ import dynamic from 'next/dynamic' import type { ReactNode } from 'react' import { lazy, Suspense, useMemo, useState } from 'react' +import { HighLighterPrismCdn } from '~/components/ui/code-highlighter' import { ShikiHighLighterWrapper } from '~/components/ui/code-highlighter/shiki/ShikiWrapper' import { parseShouldCollapsedFromAttrs } from '~/components/ui/code-highlighter/shiki/utils' import { ExcalidrawLoading } from '~/components/ui/excalidraw/ExcalidrawLoading' @@ -64,37 +65,39 @@ export const CodeBlockRender = (props: { const { lang } = props const nextProps = { ...props } nextProps.content = formatCode(props.content) - const ShikiHighLighter = - shikiImport ?? - lazy(() => - import('~/components/ui/code-highlighter/shiki/Shiki').then( - (mod) => ({ - default: mod.ShikiHighLighter, - }), - ), + if (lang) { + const ShikiHighLighter = + shikiImport ?? + lazy(() => + import('~/components/ui/code-highlighter').then((mod) => ({ + default: mod.ShikiFallback, + })), + ) + if (isClientSide) { + shikiImport = ShikiHighLighter + } + + const fallback = ( + +
+                
+                  {nextProps.content}
+                
+              
+
+ ) + if (!isClientSide) return fallback + return ( + + + ) - if (isClientSide) { - shikiImport = ShikiHighLighter } - const fallback = ( - -
-              
-                {nextProps.content}
-              
-            
-
- ) - if (!isClientSide) return fallback - return ( - - - - ) + return } } }, [props]) diff --git a/src/components/ui/code-highlighter/CodeHighlighter.tsx b/src/components/ui/code-highlighter/CodeHighlighter.tsx index 91953bb8c44..74f166e9de0 100644 --- a/src/components/ui/code-highlighter/CodeHighlighter.tsx +++ b/src/components/ui/code-highlighter/CodeHighlighter.tsx @@ -1,6 +1,13 @@ import type React from 'react' import type { FC } from 'react' -import { useCallback, useEffect, useInsertionEffect, useRef } from 'react' +import { + use, + useCallback, + useEffect, + useInsertionEffect, + useMemo, + useRef, +} from 'react' import { useIsPrintMode } from '~/atoms/css-media' import { useIsDark } from '~/hooks/common/use-is-dark' @@ -10,6 +17,8 @@ import { loadScript, loadStyleSheet } from '~/lib/load-script' import { toast } from '~/lib/toast' import styles from './CodeHighlighter.module.css' +import type { ShikiProps } from './shiki/Shiki' +import { ShikiHighLighter } from './shiki/Shiki' declare global { interface Window { @@ -140,3 +149,22 @@ const useLoadHighlighter = (ref: React.RefObject) => { }) }, []) } +let bundledLanguagesKeysSet: Set | null = null +export const ShikiFallback: FC = (props) => { + const { lang } = props + const shikiSupported = use( + useMemo(async () => { + if (!lang) return false + + if (!bundledLanguagesKeysSet) { + const { bundledLanguages } = await import('shiki/langs') + bundledLanguagesKeysSet = new Set(Object.keys(bundledLanguages)) + } + + return bundledLanguagesKeysSet.has(lang) + }, [lang]), + ) + return ( + + ) +} diff --git a/src/components/ui/code-highlighter/shiki/Shiki.tsx b/src/components/ui/code-highlighter/shiki/Shiki.tsx index d9f39652a2b..32943e56e0c 100644 --- a/src/components/ui/code-highlighter/shiki/Shiki.tsx +++ b/src/components/ui/code-highlighter/shiki/Shiki.tsx @@ -48,7 +48,7 @@ export const ShikiHighLighter: FC = (props) => { const { bundledLanguages } = await import('shiki/langs') - if (!language || !(bundledLanguages as any)[language]) return + if (!language) return const importFn = (bundledLanguages as any)[language] if (!importFn) return return loadShikiLanguage(language || '', importFn)