prism-react-renderer 扩展语言模块
github:github.com/FormidableL...
demo:github.com/FormidableL...
prism-react-renderer
是基于 Prism.js
的 React 封装库,解决了 Prism.js
在代码更新时直接操作 DOM、从而破坏 React Diff 算法的问题。 使用 prism-react-renderer
时,代码的更新不会触发整个组件 DOM 的重绘,因而更加高效和稳定。
prism-react-renderer
本身支持的语言是有限的
arduino
export const languagesToBundle = <const>[
"markup",
"jsx",
"tsx",
"swift",
"kotlin",
"objectivec",
"js-extras",
"reason",
"rust",
"graphql",
"yaml",
"go",
"cpp",
"markdown",
"python",
"json",
]
添加语言支持的关键步骤是在组件渲染之前,先加载并注册新的语言定义。
1.安装语言模块
首先,你需要通过 npm 或 yarn 安装所需的 Prism.js 语言组件。例如,要添加 Kotlin 支持:
bash
npm install prismjs/components/prism-kotlin
2.在组件中引入并注册语言
然后,在你的 React 组件文件中,在导入 Highlight
组件之后 ,立即通过 import
或 require
语句引入对应的语言模块。
javascript
// 1. 引入 prism-react-renderer 的核心组件
import { Highlight, Prism } from "prism-react-renderer";
// 2. 关键步骤:将 Prism 实例设置为全局变量,以便语言插件可以注册自己
// 注意:以下两种方式选择其一即可
// 方式一:适用于现代前端环境(如Webpack 5+可能没有全局的global或window)
import Prism from 'prismjs';
(typeof global !== "undefined" ? global : window).Prism = Prism;
// 方式二:或者直接绑定到全局对象
(typeof globalThis !== "undefined" ? globalThis : window).Prism = Prism;
// 3. 动态导入或要求你需要的特定语言
// 使用 ES6 动态导入 (异步)
import("prismjs/components/prism-kotlin");
import("prismjs/components/prism-swift");
// ... 导入其他所需语言
// 或者使用 require (同步)
require("prismjs/components/prism-kotlin");
require("prismjs/components/prism-swift");
// 4. 现在你可以在组件中使用这些语言了
const YourCodeComponent = ({ code }) => {
return (
<Highlight Prism={Prism} code={code} language="kotlin">
{/* ... 你的渲染逻辑 ... */}
</Highlight>
);
};
!注意:
1.一定注意需要将
prism-react-renderer
中的Prism与Prismjs
的Prism实例为同一个,并且同步挂载到全局2.语言模块的加载和注册必须在包含
<Highlight>
的组件渲染之前完成
在工程化环境中
推荐结合工具方法实现 文件名 → 语言识别 → 动态加载。
以下是我写的实例
步骤
javascript
// 1.引入初始化实例
import { Highlight, themes, Prism } from 'prism-react-renderer'
(typeof global !== "undefined" ? global : window).Prism = Prism
// 2.获取文件包,通过 getLangFromFileName 方法指定语言语法
const detectedLanguage = getLangFromFileName(filename)
// 3.通过hook 与 语言语法 动态加载素材包
usePrismLanguageLoader(detectedLanguage)
1. 根据文件名推断语言
获取文件包 getLangFromFileName 方法
dart
// 分别建立 LANGUAGE_MAP 、 SPECIAL_FILE_MAP 、 COMPOUND_EXTENSIONS 分别为普通文件后缀名 、 特殊文件名 、 特殊复合文件名
// 其中 PRISM_LANGUAGE_MAP 样式为
export const LANGUAGE_MAP: Record<string, string> = {
'.js': 'javascript'
.......
}
export function getLangFromFileName(fileName: string): string {
if (!fileName) return 'text'
const lowerFileName = fileName.toLowerCase()
const baseName = lowerFileName.split('/').pop() || ''
if (SPECIAL_FILE_MAP[baseName]) {
return SPECIAL_FILE_MAP[baseName]
}
for (const [extension, language] of Object.entries(COMPOUND_EXTENSIONS)) {
if (lowerFileName.endsWith(extension)) {
return language
}
}
const lastPart = lowerFileName.match(/.[^./\]+$/)
if (lastPart) {
const extension = lastPart[0]
return LANGUAGE_MAP[extension] ?? 'text'
}
return 'text'
}
2.动态加载语言定义
usePrismLanguageLoader
typescript
// 声明缓存位置
const loadedLanguages = new Set<string>()
const PRISM_LANGUAGE_MAP: Record<string, () => Promise<any>> = {
java: () => import('prismjs/components/prism-java'),
}
export function usePrismLanguageLoader(language: string) {
useEffect(() => {
if (language === 'text' || loadedLanguages.has(language)) {
return
}
const languageLoader = PRISM_LANGUAGE_MAP[language]
if (!languageLoader) {
return
}
languageLoader().then(() => {
loadedLanguages.add(language)
}).catch(() => {
//
})
}, [language])
return
}
3.综合使用
ini
import { Highlight, Prism } from "prism-react-renderer";
(globalThis as any).Prism = Prism;
const CodeBlock = ({ code, filename }: { code: string; filename: string }) => {
const lang = getLangFromFileName(filename);
usePrismLanguageLoader(lang);
return (
<Highlight {...defaultProps} code={fileContent} language={detectedLanguage} theme={theme.github}>
{({ tokens, getLineProps, getTokenProps }) => (
<List
height={500} // 可视区域高度
itemCount={tokens.length} // 总行数
itemSize={20} // 每行高度
width="100%" // 列表宽度
>
{({ index, style }) => (
<div style={style} {...getLineProps({ line: tokens[index], key: index })}>
{tokens[index].map((token, key) => (
<span key={key} {...getTokenProps({ token, key })} />
))}
</div>
)}
</List>
)}
</Highlight>
);
};
参考文章:
关于prism-react-renderer在nextjs中的动态导入prism-react-renderer是基于pr - 掘金