本站基于 Next.js RSC 的代码高亮实现方法
本站是基于 Next.js 15
RSC 的,使用 next-mdx-remote 编译 Markdown 文件, rehype-pretty-code 插件实现代码高亮,先看一下实现的效果。
实现效果
JS 代码高亮
js
function myFunction() {
const iterable = [10, 20, 30];
for (const value of iterable) {
console.log(value);
}
}
行高亮,2~3 行和第 5 行,语法 js {2-3,5}
js
function myFunction() {
const iterable = [10, 20, 30];
for (const value of iterable) {
console.log(value);
}
}
关键字高亮,语法 js /Nshen/
js
const name = "Nshen";
function myFunction() {
const iterable = [10, 20, 30];
for (const value of iterable) {
console.log(value);
}
}
高亮组,语法 js /age/#1 /name/#1 /setAge/#2 /setName/#2 /40/#3 /"Nshen"/#3
js
const [age, setAge] = useState(40);
const [name, setName] = useState("Nshen");
高亮 Inline Code [1, 2, 3] {a:'aaa', str:'bbb', num: 123, b: true}
语法为
js
`[1, 2, 3] {a:'aaa', str:'bbb', num: 123, b: true}{:js}`
显示行号和代表标题 js showLineNumbers title="以下代码显示了行号"
js
function myFunction() {
const iterable = [10, 20, 30];
for (const value of iterable) {
console.log(value);
}
}
function myFunction() {
const iterable = [10, 20, 30];
for (const value of iterable) {
console.log(value);
}
}
实现方法
核心代码在 24 行,当编译 mdx
文件的时候,在 rehypePlugins
中传入 rehype-pretty-code
插件
typescript
import { compileMDX } from "next-mdx-remote/rsc";
import rehypePrettyCode from "rehype-pretty-code";
// rehypePrettyCode options
const options = {
// Use one of Shiki's packaged themes
// https://shiki.style/themes#themes
theme: "one-dark-pro",
// Keep the background or use a custom background color?
keepBackground: true,
defaultLang: "plaintext",
};
export async function compile(source: string): Promise<{
content: JSX.Element;
frontmatter: Record<string, unknown>;
}> {
const result = await compileMDX({
source,
options: {
parseFrontmatter: true,
mdxOptions: {
remarkPlugins: [remarkGfm],
rehypePlugins: [[rehypePrettyCode, options]],
format: "mdx",
},
},
components: mdxComponents,
});
if (!result) {
throw new Error("MDX result undefined");
}
return result;
}
传入插件后观察编译后的结构中多了很多类似 data-rehype-pretty-code-figure
的属性,这个叫做Data attributes 。
CSS 有专门的选择器可以针对生成的标签添加样式。由于本站是基于 Next.js 和 Tailwind 的,所以可以直接在 global.css
这个文件中继续添加样式。
css
/* 删除多余的 ` 符号 */
[data-rehype-pretty-code-figure] code::before{
content: none;
}
[data-rehype-pretty-code-figure] code::after{
content: none
}
figure[data-rehype-pretty-code-figure] pre {
@apply py-4 overflow-x-auto rounded-lg leading-7
}
/* 代码块边距 */
pre [data-line] {
@apply px-4
}
/* title */
[data-rehype-pretty-code-title] {
@apply ml-1
}
/* Group 高亮 */
[data-highlighted-chars] {
@apply border-b-2 rounded p-1 font-bold border-red-700 text-red-300 bg-red-950
}
[data-chars-id="1"] {
@apply border-b-2 rounded p-1 font-bold border-red-600 text-red-300 bg-red-900
}
[data-chars-id="2"] {
@apply border-b-2 rounded p-1 font-bold border-green-600 text-green-300 bg-green-900
}
[data-chars-id="3"] {
@apply border-b-2 rounded p-1 font-bold border-cyan-600 text-cyan-300 bg-cyan-900
}
[data-chars-id="4"] {
@apply border-b-2 rounded p-1 font-bold border-blue-600 text-blue-300 bg-blue-900
}
/* 行号实现 */
[data-line-numbers] {
counter-reset: line;
}
[data-line-numbers] [data-line]::before {
counter-increment: line;
content: counter(line);
display: inline-block;
width: 1rem;
margin-right: 1rem;
text-align: right;
@apply text-sm text-gray-600;
}
/* inline */
span[data-rehype-pretty-code-figure] code {
@apply bg-gray-200 text-black text-sm font-normal px-2 py-1 mx-1 rounded !important
}
span[data-highlighted-line] {
@apply bg-slate-300 bg-opacity-10;
}
我不是 CSS 专家,以上是我调试很久得到的效果,尽量做到了美观简洁,也欢迎分享你的样式。