一、为什么选择Prism.js?——轻量、易用与生态优势
在为技术博客、文档站或开发者平台选型代码高亮方案时,你很可能已在 Highlight.js、Shiki 和 Prism.js 之间犹豫。而越来越多的现代静态站点(Hugo/Jekyll/VitePress)和框架应用(Vue 3、React 18+、SvelteKit)正将 Prism.js 作为默认首选——这不是偶然。
Prism 的核心竞争力在于「精准克制」:它零运行时依赖(纯原生 JS),无构建强制要求(CDN 开箱即用),且语言与插件完全解耦。对比 Highlight.js(需手动注册语言、CSS 主题强耦合、SSR 友好性较弱),Prism 的模块化设计天然适配按需加载:你只需引入 prism-core.js + prism-javascript.js + prism-coy.css,就能获得一个仅 12KB(gzip)的 JS 高亮内核。
更关键的是,Prism 对 Markdown 生态的原生友好性极强。主流渲染器(Remark/Rehype、VitePress 的 @mdx-js/mdx、Hugo 的 Goldmark)默认输出符合 Prism 规范的 HTML 结构:
<pre><code class="language-js">console.log('Hello Prism!');</code></pre>
无需额外配置解析器或自定义语法树转换——这为后续集成省去了大量胶水代码。同时,其 CSS-in-JS 友好特性(如通过 Prism.plugins.NormalizeWhitespace 处理缩进、支持 data-language 属性驱动)也让它轻松融入 Tailwind、UnoCSS 或 CSS Modules 工程体系。
💡 小贴士:Prism 官方提供 下载定制器,可勾选所需语言/插件后一键生成精简版 CDN 链接——这是避免“全量打包却只用 JS”的第一道防线。
二、三步完成基础集成——CDN引入 + 自动高亮
无需构建工具,3 分钟即可让代码块焕然一新:
✅ 步骤1:引入精简版 CDN
访问 prismjs.com/download,勾选 JavaScript、CSS、Line Numbers(可选)及主题(如 Prism 或 Night Owl),复制生成的 <link> 和 <script>:
<link href="https://cdn.jsdelivr.net/npm/[email protected]/themes/prism.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/[email protected]/components/prism-core.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/plugins/autoloader/prism-autoloader.min.js"></script>
<!-- 按需加载核心语言 -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/components/prism-javascript.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/components/prism-css.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/components/prism-html.min.js"></script>
⚠️ 注意:JS 与 CSS 版本号必须严格一致(如均为
1.29.0),否则 token 类名可能不匹配导致样式失效。
✅ 步骤2:确保 HTML 结构合规
Prism 默认识别 <code class="language-xxx">。Markdown 渲染后应生成:
<pre><code class="language-js">function greet() { return 'Hi!'; }</code></pre>
若渲染器未自动添加 language- 前缀(如某些旧版 Hugo),可手动加 data-language="js":
<pre><code data-language="js">...</code></pre>
✅ 步骤3:初始化高亮
在 </body> 前添加脚本(含 DOM 加载安全检查):
<script>
document.addEventListener('DOMContentLoaded', () => {
// 避免重复执行(尤其 SPA 中)
if (!window.Prism || !Prism.highlightAll) return;
Prism.highlightAll();
});
</script>
完整 HTML 示例:
<!DOCTYPE html>
<html>
<head>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/themes/prism.min.css" rel="stylesheet">
</head>
<body>
<pre><code class="language-js">console.log('It works!');</code></pre>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/components/prism-core.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/components/prism-javascript.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => Prism.highlightAll());
</script>
</body>
</html>
三、按需加载语言与插件——减小包体积实战
当站点支持 15+ 语言时,全量加载会显著拖慢首屏。Prism 的 manual 模式是破局关键:
🔧 禁用自动高亮 + 精准控制
// 全局禁用自动执行
Prism.manual = true;
// 手动高亮指定元素
const codeBlock = document.querySelector('pre code');
if (codeBlock) Prism.highlightElement(codeBlock);
🌐 动态导入语言(ESM 示例)
// React 中的动态高亮 Hook
import { useEffect, useRef } from 'react';
export function usePrismHighlight(lang) {
const ref = useRef(null);
useEffect(() => {
if (!ref.current) return;
const loadAndHighlight = async () => {
try {
await import(`prismjs/components/prism-${lang}.js`);
Prism.highlightElement(ref.current);
} catch (err) {
console.warn(`Failed to load Prism language: ${lang}`, err);
}
};
loadAndHighlight();
}, [lang]);
return ref;
}
// 使用
function CodeBlock({ lang, children }) {
const ref = usePrismHighlight(lang);
return <pre><code ref={ref} className={`language-${lang}`}>{children}</code></pre>;
}
🧩 插件启用指南
autoloader:自动根据class="language-toml"加载prism-toml.js(需配合prism-autoloader.js和prismjs/plugins/autoloader/路径配置)show-language:在代码块右上角显示语言标签(需额外 CSS)copy-to-clipboard:添加复制按钮(需 HTTPS 环境)
⚠️ SSR 注意:
Prism.highlightElement()是浏览器 API,服务端渲染时需包裹if (typeof window !== 'undefined')判断。
四、定制主题——从 CSS 覆盖到主题生成器
不必从头写 CSS,三种渐进式定制方案:
方式1:CSS 变量覆盖(推荐!)
Prism v1.27+ 支持 CSS 自定义属性,适配深色模式:
:root {
--prism-background: #f8f9fa;
--prism-color: #212529;
--prism-comment: #6c757d;
--prism-keyword: #007bff;
}
@media (prefers-color-scheme: dark) {
:root {
--prism-background: #1e1e1e;
--prism-color: #e0e0e0;
--prism-comment: #6a9955;
--prism-keyword: #569cd6;
}
}
/* 必须保留 .token 层级 */
.token.comment { color: var(--prism-comment); }
.token.keyword { color: var(--prism-keyword); }
.token { background: var(--prism-background); color: var(--prism-color); }
方式2:主题生成器一键导出
访问 Prism Theme Generator,调整颜色后点击 Export CSS,替换原有 <link> 即可。
方式3:Sass 工程化重构
安装源码:npm install prismjs,在 Sass 中:
$prism-bg: #2d2d2d;
$prism-fg: #f8f8f2;
@import 'prismjs/themes/prism.scss';
⚠️ 避坑:禁用
!important;所有.token.*类必须显式声明;务必测试punctuation、operator、regex等边缘 token。
五、进阶技巧与避坑指南
🔗 行号与折叠插件兼容性
line-numbers 与 diff-highlight 同时启用时,需确保 line-numbers 在 diff-highlight 之后加载,否则行号错位:
<script src="prism-diff-highlight.js"></script>
<script src="prism-line-numbers.js"></script> <!-- 后加载 -->
⏱ 动态渲染时机问题
- Vue:在
onUpdated或nextTick中调用Prism.highlightElement - React:在
useEffect中监听codeRef.current变化,避免重复高亮
🌐 SSR 首屏无高亮修复
服务端不执行 JS → 客户端 hydration 后补全:
// Next.js / Nuxt 中
if (typeof window !== 'undefined') {
// 延迟到 hydration 后执行
setTimeout(() => Prism.highlightAll(), 0);
}
❓常见问题速查
| 问题 | 解决方案 |
|---|---|
| 代码显示为纯文本 | 检查 <code> 是否有 language-xxx class;确认 Prism JS/CSS 加载顺序正确 |
| TOML/MDX 不高亮 | 显式引入 prism-toml.js 或 prism-mdx.js(非默认语言) |
| 复制按钮无效 | 确认启用 copy-to-clipboard 插件;检查是否在 HTTPS 环境;验证 navigator.clipboard.writeText 权限 |
六、验证与性能优化 checklist
✅ 手动测试清单:
- 主流语言:JS/TS、Python、HTML、CSS、Shell(含
$提示符) - 边界场景:4空格缩进、
\n换行、<>转义、超长单行(测试white-space: pre-wrap)
✅ Lighthouse 优化:
<link
href="prism.min.css"
rel="stylesheet"
fetchpriority="low"
media="print"
onload="this.media='all'"
>
✅ Bundle 分析验证:
使用 rollup-plugin-visualizer 或 source-map-explorer,确认 node_modules/prismjs/components/ 下仅存在已启用的语言文件。
✅ 一键检测脚本(粘贴至浏览器控制台):
console.log(
'高亮完成率:',
[...document.querySelectorAll('pre code')].filter(el =>
el.classList.contains('language-js') && el.classList.contains('language-python')
).length,
'/',
document.querySelectorAll('pre code').length
);
🎯 最后建议:启用 Prism 构建时
--minify选项(npx prismjs --languages=javascript,css,html --plugins=line-numbers --minify > prism.min.js),进一步压缩体积。
掌握这些技巧,你不仅能快速落地代码高亮,更能将其深度融入工程体系——轻量、可控、可维护。现在,就打开你的博客,给第一段 console.log() 加上色彩吧!