Skip to content

Commit

Permalink
feat: shiki fully support
Browse files Browse the repository at this point in the history
Signed-off-by: Innei <i@innei.in>
  • Loading branch information
Innei committed Apr 18, 2024
1 parent 2b7f89f commit 42e21cc
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 59 deletions.
11 changes: 4 additions & 7 deletions src/components/modules/shared/CodeBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import type { ReactNode } from 'react'

import { HighLighterPrismCdn } from '~/components/ui/code-highlighter'
import { ShikiHighLighterWrapper } from '~/components/ui/code-highlighter/shiki/ShikiWrapper'
import { isSupportedShikiLang } from '~/components/ui/code-highlighter/shiki/utils'
import { ExcalidrawLoading } from '~/components/ui/excalidraw/ExcalidrawLoading'
import { isClientSide } from '~/lib/env'

Expand Down Expand Up @@ -65,15 +64,13 @@ export const CodeBlockRender = (props: {
const lang = props.lang
const nextProps = { ...props }
nextProps.content = formatCode(props.content)
if (lang && isSupportedShikiLang(lang)) {
if (lang) {
const ShikiHighLighter =
shikiImport ??
lazy(() =>
import('~/components/ui/code-highlighter/shiki/Shiki').then(
(mod) => ({
default: mod.ShikiHighLighter,
}),
),
import('~/components/ui/code-highlighter').then((mod) => ({
default: mod.ShikiFallback,
})),
)
if (isClientSide) {
shikiImport = ShikiHighLighter
Expand Down
25 changes: 25 additions & 0 deletions src/components/ui/code-highlighter/CodeHighlighter.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import React, {
use,
useCallback,
useEffect,
useInsertionEffect,
useMemo,
useRef,
} from 'react'
import type { FC } from 'react'
import type { ShikiProps } from './shiki/Shiki'

import { useIsPrintMode } from '~/atoms/css-media'
import { useIsDark } from '~/hooks/common/use-is-dark'
Expand All @@ -14,6 +17,7 @@ import { loadScript, loadStyleSheet } from '~/lib/load-script'
import { toast } from '~/lib/toast'

import styles from './CodeHighlighter.module.css'
import { ShikiHighLighter } from './shiki/Shiki'

declare global {
interface Window {
Expand Down Expand Up @@ -146,3 +150,24 @@ const useLoadHighlighter = (ref: React.RefObject<HTMLElement>) => {
})
}, [])
}
let bundledLanguagesKeysSet: Set<string> | null = null
export const ShikiFallback: FC<ShikiProps> = (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]),
)

if (!shikiSupported) {
return <HighLighterPrismCdn {...props} />
}
return <ShikiHighLighter {...props} />
}
55 changes: 30 additions & 25 deletions src/components/ui/code-highlighter/shiki/Shiki.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { isServerSide } from '~/lib/env'

import { ShikiHighLighterWrapper } from './ShikiWrapper'

interface Props {
export interface ShikiProps {
lang: string | undefined
content: string

Expand All @@ -21,42 +21,47 @@ const codeHighlighterPromise = (async () => {
import('./core'),
])

const loaded = await getHighlighterCore({
const core = await getHighlighterCore({
themes: [
import('shiki/themes/github-light.mjs'),
import('shiki/themes/github-dark.mjs'),
],
langs: [
() => import('shiki/langs/javascript.mjs'),
() => import('shiki/langs/typescript.mjs'),
() => import('shiki/langs/css.mjs'),
() => import('shiki/langs/tsx.mjs'),
() => import('shiki/langs/jsx.mjs'),
() => import('shiki/langs/json.mjs'),
() => import('shiki/langs/sql.mjs'),
() => import('shiki/langs/rust.mjs'),
() => import('shiki/langs/go.mjs'),
() => import('shiki/langs/cpp.mjs'),
() => import('shiki/langs/c.mjs'),
() => import('shiki/langs/markdown.mjs'),
() => import('shiki/langs/vue.mjs'),
() => import('shiki/langs/html.mjs'),
() => import('shiki/langs/asm.mjs'),
() => import('shiki/langs/shell.mjs'),
() => import('shiki/langs/ps.mjs'),
],
langs: [],
loadWasm: getWasm,
})

return (o: { lang: string; attrs: string; code: string }) =>
codeHighlighter(loaded, o)
return {
codeHighlighter: core,
fn: (o: { lang: string; attrs: string; code: string }) => {
return codeHighlighter(core, o)
},
}
})()

export const ShikiHighLighter: FC<Props> = (props) => {
export const ShikiHighLighter: FC<ShikiProps> = (props) => {
const { lang: language, content: value, attrs } = props
const codeHighlighter = use(codeHighlighterPromise)

use(
useMemo(async () => {
async function loadShikiLanguage(language: string, languageModule: any) {
const shiki = codeHighlighter?.codeHighlighter
if (!shiki) return
if (!shiki.getLoadedLanguages().includes(language)) {
await shiki.loadLanguage(await languageModule())
}
}

const { bundledLanguages } = await import('shiki/langs')

if (!language) return
const importFn = (bundledLanguages as any)[language]
if (!importFn) return
return loadShikiLanguage(language || '', importFn)
}, [codeHighlighter?.codeHighlighter, language]),
)
const highlightedHtml = useMemo(() => {
return codeHighlighter?.({
return codeHighlighter?.fn?.({
attrs: attrs || '',
// code: `${value.split('\n')[0].repeat(10)} // [!code highlight]\n${value}`,
code: value,
Expand Down
34 changes: 7 additions & 27 deletions src/components/ui/code-highlighter/shiki/utils.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// import { bundledLanguages } from 'shiki/langs'

export const parseFilenameFromAttrs = (attrs: string) => {
// filename=""

Expand All @@ -8,32 +10,10 @@ export const parseFilenameFromAttrs = (attrs: string) => {
return null
}

// const shikiSupportLangSet = new Set(Object.keys(bundledLanguages))
export const isSupportedShikiLang = (lang: string) => {
return [
'javascript',
'typescript',
'ts',
'js',
'css',
'tsx',
'jsx',
'json',
'sql',
'markdown',
'vue',
'rust',
'go',
'cpp',
'c',
'html',
'asm',
'bash',
'ps',
'ps1',
// plain text
'text',
'plaintext',
'txt',
'plain',
].includes(lang.toLowerCase())
// require esm error, fuck nextjs 14.12.x
// @see https://github.com/vercel/next.js/issues/64434
// return shikiSupportLangSet.has(lang)
return true
}

0 comments on commit 42e21cc

Please sign in to comment.