接續上一講專案的基礎建立後,我們已經能用基本的 Markdown 透過 Astro Layout 及其本身對 Markdown 格式的轉譯,產生出一篇 HTML 格式的頁面了。
然而若是我們想要加入更多型態的內容在文章中,例如程式碼、數學式,應該怎麼設定?甚至還要寫點互動式的內容,除了透過 .astro 的模板,能夠更統一的用 Markdown 的形式來撰文嗎?這講就來聊聊怎麼達成這些目標。
倘若我們想要保有彈性,但又不想用「類 HTML」的 Tag 語法(也就是 .astro)來做,那就可以試試看 MDX 這種格式。
所謂的 MDX,基本上就是在 Markdown 的架構底下,同時也能插入 JSX 的語法(一種在 JavaScript 中寫 XML/HTML Markup 的語法擴充)。
在使用之前,我們一樣需要透過 npm install @astrojs/mdx 安裝 Astro 的 MDX 套件。並且在 astro.config.ts 中加入以下內容:
import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
import mdx from '@astrojs/mdx'; // Added
export default defineConfig({
  integrations: [react(), mdx()], // Updated
});
如此一來就可以開始撰寫 MDX 的文章了。新增 src/pages/posts/third-post.mdx 的檔案。
還記得我們上一講剛剛建立過稱作 Greeting 的 Astro Component 對吧?這樣的 Component 可以直接整合進 MDX 的文章中:
---
layout: ../../layouts/BlogPostLayout.astro
title: '第三篇部落格貼文'
publishedTime: '2025-05-08 23:12:00'
updatedTime: '2025-05-08 23:12:00'
---
import Greeting from '../../components/Greeting.astro';
# The Third Blog Post
<Greeting name="John" />
MDX 是在最上方也保有 Frontmatter 記錄一些文章的基礎資訊,例如標題、新增及更新時間等等,也一樣可以透過 layout 裡面指定我們寫好的 BlogPostLayout 路徑即可,和 Markdown 到目前為止一模一樣。
額外增加的是正文中的部分,我們在 MDX 中可以使用 JavaScript 的語法了,例如 import 指令,以及直接使用 <Greeting /> 的 Component。
除了基本的標題、段落文字,還有我們在 MDX 能插入的 JavaScript、寫好的 Astro / React 元件之外,也來簡單介紹一下 Astro,或是大多數的 Markdown 轉換器能夠將怎麼樣的內容轉換成 HTML。
以下是 Markdown 元素和 HTML 元素的轉換對應表
| 名稱 | Markdown 範例 | 轉成的 HTML | 
|---|---|---|
| 標題 | # Title,## Title, … | <h1>Title</h1>,<h2>Title</h2>, … | 
| 段落 | (透過空白行分隔段落) | <p>...</p> | 
| 換行 | (行尾兩格空白換行) | <br> | 
| 斜體 | _italic_ | <em>italic</em> | 
| 粗體 | **bold** | <strong>bold</strong> | 
| 行內程式碼 | `int i = 0;` | <code>int i = 0;</code> | 
| 程式碼 | ```console.log('hello');``` | <pre><code>console.log('hello');</code></pre> | 
| 引用區塊 | > quote | <blockquote><p>quote</p></blockquote> | 
| 無序列表 | - item/* item | <ul><li>item</li></ul> | 
| 有序列表 | 1. item | <ol><li>item</li></ol> | 
| 分隔線 | --- | <hr> | 
| 連結 | [link](https//md.com) | <a href="https://md.com">link</a> | 
| 圖片 |  | <img src="img.png" alt="alt"> | 
其餘還有一些常見的擴充,例如刪節線、表格、待辦清單等等,GitHub 將這些擴充打包並定義了 GFM(GitHub Flavored Markdown),也就是 GitHub 的網頁中能直接呈現的 Markdown 元素。
如果要在 Astro 當中使用與 GitHub 一樣的擴充,可以透過 npm install remark-gfm 並且在 astro.config.ts 裡面加入設定。
import remarkGfm from 'remark-gfm'; // Added
export default defineConfig({
  integrations: [mdx(remarkGfm)], // Updated
});
有了基本的文章元素後,身為工程師,寫點數學式子也是人之常情吧!但大多數的 Markdown 轉換器都不會原生支援,因為相比於單純的文章,在撰寫數學式上需要的是完全的另一套複雜系統。
通常在一些專業的學術刊物上,會使用 LaTeX 作為排版和產生數學式子等內容的系統。想在網頁上渲染 LaTeX 的數學式,則有常見的兩種 Libraries 來做選擇:KaTeX 或是 MathJax。
LaTeX 是一種基於 TeX 的排版系統,也是一種 Markup Language,前者由 2013 年圖靈獎得主 Leslie Lamport 所開發,而後者則是由著名「電腦程式設計藝術」的作者高德納所發明。LaTex 使用 TeX 作為其格式化引擎,可以讓使用者沒有排版的知識也能產出專業品質的刊物。
而 KaTeX 和 MathJax 都是 JavaScript 的 Library,前者由 Khan Academy 開發、後者由美國數學學會管理,兩者主要的差異在於:
既然我的目的是以撰寫部落格為主,簡單的數學式就能滿足我大部分需求了,不需要到更專業的學術等級;那考慮就是渲染速度了,較快的 KaTeX 就成為我的首選。
選定了 KaTeX 後,接著就來整合進現有的 Astro 專案吧!首先是相關套件的安裝:npm install katex remark-math rehype-katex。
除了本體的 katex 外,還需要 remark-math 來解析 Markdown 中的數學式子,畢竟我們大部分的情境會在 Markdown 底下撰文;而 rehype-katex 則將解析完的式子渲染成 KaTeX 所需的 HTML 結構。
安裝完畢後,再來需要修改 astro.config.ts 的內容,將 remark-math 及 rehype-katex 加入到 integration 的 mdx 下。
import remarkMath from 'remark-math'; // Added
import rehypeKatex from 'rehype-katex'; // Added
export default defineConfig({
  // Updated
  integrations: [mdx({ remarkPlugins: [remarkMath], rehypePlugins: [rehypeKatex] })],
}
再來可以在全域或特定的 Layout 中匯入 KaTeX 的樣式,例如在部落格的模板 BlogPostLayout.astro 中的加入 import 'katex/dist/katex.min.css';。
最後就能快樂寫算式了,隨便挑一篇 MDX 或 Markdown 的文章,在內文中加入:
Formula 1 - $E = mc^2$
Formula 2 - $\int_0^1 x^2 dx = \frac{1}{3}$
Formula 3:
$$
\begin{array}{l r}
F = ma & \text{(1)} \\
E_k = \frac{1}{2}mv^2 & \text{(2)}
\end{array}
$$
便能顯示精美的數學式。

*KaTex 產出結果