prism-react-renderer 扩展语言模块

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 组件之后 ,立即通过 importrequire 语句引入对应的语言模块。

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 - 掘金

相关推荐
matrixmind14 小时前
Nivo 用React打造精美数据可视化的开源利器
其他·react.js·信息可视化·开源
BrendanDash9 小时前
React 19.2 已发布,现已上线 npm!
前端·react.js
Winson℡19 小时前
React Native 中的 useCallback
javascript·react native·react.js
二狗mao1 天前
React学习(一)描述UI
react.js
一只猪皮怪51 天前
React 18 前端最佳实践技术栈清单(2025版)
前端·react.js·前端框架
Misnice1 天前
React渲染超大的字符串
前端·javascript·react.js
带娃的IT创业者2 天前
TypeScript + React + Ant Design 前端架构入门:搭建一个 Flask 个人博客前端
前端·react.js·typescript
千叶寻-2 天前
package.json详解
前端·vue.js·react.js·webpack·前端框架·node.js·json
光影少年2 天前
react打包优化和配置优化都有哪些?
前端·react.js·掘金·金石计划