在技術 Blog 中,程式碼區塊幾乎是最重要的內容之一。
如果只是使用普通 Markdown 顯示程式碼,通常只會是單純的文字區塊,閱讀體驗並不理想。常見的技術文章網站都會有語法高亮(Syntax Highlighting),讓程式碼更容易閱讀。
在 Next.js + MDX 的 Blog 中,一個很常見的做法是使用 Shiki 搭配 rehype-pretty-code。
為什麼選擇 Shiki?
Shiki 是 VS Code 底層使用的語法高亮引擎,也就是說,Shiki 的高亮效果基本上就是 VS Code 的顯示效果。
- 支援大量程式語言
- 顏色主題豐富(內建 VS Code 所有主題)
- 高亮效果非常準確
- 與 MDX 生態系整合良好
安裝套件
npm install rehype-pretty-code shiki設定步驟
第一步:修改 lib/posts.ts
在 compileMDX 的 rehypePlugins 陣列中加入 rehype-pretty-code:
import rehypePrettyCode from "rehype-pretty-code";
import rehypeSlug from "rehype-slug";
import rehypeAutolinkHeadings from "rehype-autolink-headings";
// 在 getPostBySlug 裡的 compileMDX 選項加入:
const { content } = await compileMDX({
source: mdxContent,
options: {
mdxOptions: {
rehypePlugins: [
rehypeSlug,
rehypeAutolinkHeadings,
[
rehypePrettyCode,
{
theme: {
dark: "github-dark",
light: "github-light",
},
keepBackground: false,
},
],
],
},
},
});第二步:建立自訂 <pre> 元件(可選,加複製按鈕用)
rehype-pretty-code 輸出的 code block 是透過 <pre> 標籤包裝的。如果要加複製按鈕或自訂樣式,可以建立一個 Client Component 替換掉預設的 <pre>:
"use client";
import { useRef, useState } from "react";
export default function MDXPre(props: React.ComponentPropsWithoutRef<"pre">) {
const ref = useRef<HTMLPreElement>(null);
const [copied, setCopied] = useState(false);
const handleCopy = () => {
const text = ref.current?.querySelector("code")?.innerText ?? "";
navigator.clipboard.writeText(text);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
return (
<div className="relative group">
<pre ref={ref} {...props} />
<button
onClick={handleCopy}
className="absolute top-3 right-3 opacity-0 group-hover:opacity-100 transition"
>
{copied ? "已複製" : "複製"}
</button>
</div>
);
}接著在 lib/posts.ts 的 compileMDX 裡把 pre 替換掉:
import MDXPre from "@/components/MDXPre";
const { content } = await compileMDX({
source: mdxContent,
components: {
pre: MDXPre, // ← 用自訂元件替換預設的 <pre>
},
options: { /* ... */ },
});第三步:在 app/globals.css 加入 code block 基礎樣式
keepBackground: false 讓背景色由 CSS 控制,需要自己加上 code block 的樣式:
/* 程式碼區塊外框 */
.prose pre {
border-radius: 0.5rem;
border: 1px solid #e5e7eb;
overflow-x: auto;
padding: 1rem 1.25rem;
font-size: 0.875em;
}
/* 暗色模式 */
html.dark .prose pre {
background-color: #161b22;
border-color: #30363d;
}完成以上三步,code block 就會有完整的語法高亮效果。
在文章中寫 Code Block
在 MDX 文章中,只需要正常寫 Markdown code block,並在開頭指定語言:
TypeScript:
function greet(name: string) {
return `Hello, ${name}!`;
}Bash:
npm install next-mdx-remote不同語言會有不同的高亮效果,語言標籤同時也影響 rehype-pretty-code 顯示的標示文字。
進階功能
rehype-pretty-code 還有一些實用的進階功能。
標示指定行數
在語言標籤後面加上 {N},N 是要高亮的行號,例如:
```ts {2}
function greet() {
console.log("hello") // ← 這行會被標示
}
```效果如下:
function greet() {
console.log("hello")
}要讓高亮生效,globals.css 還需要加上對應 [data-highlighted-line] 的樣式(詳見第三步設定)。
顯示檔名
在語言標籤後面加上 title="檔名",例如:
```ts title="lib/utils.ts"
export function formatDate(date: string) {
return new Date(date).toLocaleDateString("zh-TW");
}
```效果如下:
export function formatDate(date: string) {
return new Date(date).toLocaleDateString("zh-TW");
}要讓 title 欄生效,globals.css 還需要加上 figcaption[data-rehype-pretty-code-title] 的樣式(詳見第三步設定)。
主題設定
rehype-pretty-code 支援同時設定暗色和亮色主題,搭配 CSS 變數切換:
[rehypePrettyCode, {
theme: {
dark: "github-dark",
light: "github-light",
},
keepBackground: false, // 背景色交給 CSS 控制
}]keepBackground: false 的好處是讓 code block 的背景色由你自己的 CSS 控制,方便統一整個網站的配色。
小結
使用 Shiki + rehype-pretty-code 的好處是:
- 高亮品質接近 VS Code,效果精準
- 與 Next.js + MDX 整合良好,設定簡單
- 支援暗色 / 亮色雙主題
- 進階功能(行高亮、檔名、diff)都有內建
對技術 Blog 來說幾乎是必備組合,強烈推薦。
下一篇會繼續介紹這個 Blog 的 TOC 目錄是怎麼做的。