4193 字
21 分钟

Astro Markdown 进阶技巧:7个让博客变专业的实用方法

用纯 Markdown 写了几篇文章后发现,能表达的东西太有限了。看别人的技术博客,代码块可以标注重点、可以展示代码改动前后的对比,文章里还能嵌入交互式的组件,自己却只能干巴巴地贴代码。

Astro 提供了 MDX 这个”增强版 Markdown”。MDX 让你在写文章的时候可以用组件、可以写 JSX,能做的事情一下子多了好几倍。

这篇文章分享 7 个 Astro Markdown/MDX 的进阶用法,从最基础的环境配置到代码高亮、自定义组件、数学公式、流程图。

从 Markdown 到 MDX#

为什么要用 MDX?#

Markdown 和 MDX 的区别,就像自行车和电动车——都能骑,但体验完全不同。

纯 Markdown 只能写文本、代码块、图片这些静态内容。你想加个提示框?得用 HTML 硬编码。想在文章里嵌入一个可交互的组件?基本没戏。

MDX 是”Markdown + JSX”的结合体。你可以:

  • 导入和使用组件:直接在 .mdx 文件里 import 任何 Astro 组件或 React/Vue 组件
  • 写 JSX 表达式:在文章里用 {variable} 插入变量,甚至写循环和条件判断
  • 自定义元素样式:把标准的 <h1> 替换成你自己的样式化组件

举个具体例子。你想在文章里加个警告框,用纯 Markdown 得这样写:

<div class="warning">
<p>注意:这个操作会删除所有数据!</p>
</div>

用 MDX 就能这样:

import Alert from '@/components/Alert.astro';
<Alert type="warning">
注意:这个操作会删除所有数据!
</Alert>

MDX 让你的文章更像是在”组装积木”,而不是”写代码”。

5分钟配置 MDX 环境#

配置 MDX 超简单,三步搞定。

第一步:安装集成包

打开终端,在你的 Astro 项目里运行:

npx astro add mdx

Astro CLI 会自动帮你安装 @astrojs/mdx 并更新配置文件。这个命令会问你几个问题(要不要更新配置、要不要安装依赖),全部选 Yes 就行。

第二步:验证配置

装完后,打开 astro.config.mjs,应该能看到这样的代码:

import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
export default defineConfig({
integrations: [mdx()],
});

如果没有自动添加,手动加上就行。

第三步:测试 MDX 是否生效

src/pages/src/content/ 目录下创建一个 test.mdx 文件:

---
title: 测试MDX
---
# 这是 MDX 测试
普通的 Markdown 文本。
export const greeting = "你好";
现在可以用变量了:{greeting}!
<div style="padding: 1rem; background: #f0f0f0;">
这是一个 JSX 元素
</div>

运行 npm run dev,访问对应页面,如果能看到变量和 JSX 元素正常显示,说明 MDX 已经配置成功了。

关于 .md 和 .mdx 文件的共存

装了 MDX 集成后,你的 .md 文件还是正常工作的。Astro 会根据文件扩展名自动选择处理方式:

  • .md 文件:按标准 Markdown 处理
  • .mdx 文件:按 MDX 处理,支持组件和 JSX

我的建议是:普通文章用 .md,需要用组件的文章用 .mdx

代码高亮的进阶技巧#

配置代码高亮主题(Shiki)#

Astro 默认用 Shiki 做代码高亮,这已经很不错了。但默认主题是 github-dark,你可能想换个更符合自己博客风格的。

Shiki vs Prism 该选哪个?

我推荐 Shiki。它是 Astro 默认的方案,支持 100 多种编程语言和主题,而且是服务端渲染的,不需要加载额外的 JavaScript。Prism 也不错,但需要引入 CSS 文件,配置相对麻烦一点。

切换内置主题

打开 astro.config.mjs,在 markdown 配置里加上 shikiConfig

import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
export default defineConfig({
integrations: [mdx()],
markdown: {
shikiConfig: {
theme: 'dracula', // 可选:github-dark, nord, monokai, dracula 等
},
},
});

Shiki 支持超多主题,我常用的有:

  • github-dark / github-light - GitHub 风格
  • dracula - 经典的紫黑配色
  • nord - 清冷的北欧风
  • one-dark-pro - VSCode 默认深色主题

你可以在 Shiki 主题预览 里挑一个自己喜欢的。

实现浅色/深色双主题切换

如果你的博客支持深浅色模式切换,Shiki 可以配置双主题:

markdown: {
shikiConfig: {
themes: {
light: 'github-light',
dark: 'github-dark',
},
},
},

这样配置后,Shiki 会根据 CSS 的 prefers-color-scheme 或你自定义的主题切换逻辑自动应用对应的代码高亮主题。

高亮特定行和代码注释#

写教程的时候,经常需要标注”看这一行很重要”或者展示”代码改了哪些地方”。Shiki Transformers 可以实现这些功能。

高亮重点代码行

先安装 Shiki 的 transformers:

npm install shiki

然后在配置里启用 transformerNotationHighlight

import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
import { transformerNotationHighlight } from '@shikijs/transformers';
export default defineConfig({
integrations: [mdx()],
markdown: {
shikiConfig: {
theme: 'github-dark',
transformers: [transformerNotationHighlight()],
},
},
});

现在可以在代码块里用 // [!code highlight] 注释来标记需要高亮的行:

```javascript
function hello() {
console.log('这行是普通的');
console.log('这行会高亮显示'); // [!code highlight]
}
```

展示代码变更(Diff 风格)

在对比”修改前/后”的代码时,可以用 transformerNotationDiff

import { transformerNotationDiff, transformerNotationHighlight } from '@shikijs/transformers';
markdown: {
shikiConfig: {
theme: 'github-dark',
transformers: [
transformerNotationHighlight(),
transformerNotationDiff(),
],
},
},

用法:

```javascript
function calculate(a, b) {
return a + b; // [!code --]
return a * b; // [!code ++]
}
```

-- 的行会显示为红色(删除),带 ++ 的行显示为绿色(新增)。这个功能写代码教程时超级实用。

聚焦特定代码

还有一个 transformerNotationFocus,可以让其他代码”变灰”,只突出你想强调的部分:

import { transformerNotationFocus } from '@shikijs/transformers';
// 添加到 transformers 数组
transformers: [
transformerNotationFocus(),
],

使用 // [!code focus] 标记:

```javascript
function process() {
console.log('这行会变灰');
console.log('这行正常显示'); // [!code focus]
console.log('这行也变灰');
}
```

升级到 Expressive Code(可选)#

如果你觉得 Shiki 的功能还不够,可以试试 Expressive Code。它是社区开发的增强版代码展示方案,提供了更多开箱即用的功能:

  • 代码块标题
  • 一键复制按钮
  • 行号显示
  • 终端窗口样式
  • 代码对比(Side-by-Side)

安装超简单

npx astro add astro-expressive-code

Astro CLI 会自动配置好一切。装完后,你的代码块就自动带上这些功能了,不需要额外配置。

什么时候用 Expressive Code?

我一开始用的是默认的 Shiki,后来发现读者经常想复制代码,就换成了 Expressive Code。如果你的博客主要是写教程、分享代码,Expressive Code 能让读者体验好很多。

但如果只是偶尔放点代码,用 Shiki + Transformers 就够了,不用增加额外的依赖。

嵌入自定义组件#

在 MDX 中导入和使用组件#

MDX 最强大的地方就是可以直接在文章里用组件。我经常用这个功能做提示框、代码对比、可折叠区域等。

创建一个警告框组件

先在 src/components/ 目录下创建一个 Alert.astro

---
interface Props {
type?: 'info' | 'warning' | 'error';
}
const { type = 'info' } = Astro.props;
const styles = {
info: 'bg-blue-50 border-blue-200 text-blue-800',
warning: 'bg-yellow-50 border-yellow-200 text-yellow-800',
error: 'bg-red-50 border-red-200 text-red-800',
};
---
<div class={`border-l-4 p-4 ${styles[type]}`}>
<slot />
</div>

在 MDX 文章中使用

在你的 .mdx 文件里导入并使用它:

---
title: 我的技术文章
---
import Alert from '@/components/Alert.astro';
# 文章标题
这是普通的文章内容。
<Alert type="warning">
注意:运行这个命令前请备份数据!
</Alert>
<Alert type="info">
提示:你也可以在组件里用 **Markdown 语法**,很方便。
</Alert>

<Alert> 组件里,你还可以继续用 Markdown 语法(如加粗、链接等),MDX 会自动处理。

使用 React/Vue 组件

MDX 不仅支持 Astro 组件,也可以用 React、Vue 等框架组件。不过要注意加上 client: 指令:

import Counter from '@/components/Counter.tsx';
<Counter client:load initialCount={0} />

client:load 表示这个组件会在页面加载时在客户端运行。如果不加,组件只会服务端渲染,交互功能不生效。

组件文件组织建议

我习惯把文章里常用的组件放在 src/components/mdx/ 目录下,这样好管理:

src/
├── components/
│ ├── mdx/
│ │ ├── Alert.astro
│ │ ├── CodeCompare.astro
│ │ ├── Callout.astro
│ │ └── Tabs.astro
│ └── ...其他组件

映射 Markdown 语法到自定义组件#

这个功能有点”黑魔法”的感觉——你可以把 Markdown 的标准元素(如 h1、a、img)替换成你自己的组件。

为什么要这么做?

比如你想给所有的标题加个锚点图标,或者给外部链接自动加个”↗“标记,手动一个个加太麻烦了。用组件映射,写标准 Markdown 就自动应用你的样式。

实战:自定义标题组件

先创建一个 CustomHeading.astro

---
interface Props {
level: 1 | 2 | 3 | 4 | 5 | 6;
id?: string;
}
const { level, id } = Astro.props;
const Tag = `h${level}` as any;
---
<Tag id={id} class="group relative">
<slot />
{id && (
<a href={`#${id}`} class="ml-2 opacity-0 group-hover:opacity-100 transition-opacity">
#
</a>
)}
</Tag>

在 MDX 中使用映射

在你的 .mdx 文件里,导出一个 components 对象:

---
title: 文章标题
---
import CustomHeading from '@/components/CustomHeading.astro';
export const components = {
h2: (props) => <CustomHeading level={2} {...props} />,
h3: (props) => <CustomHeading level={3} {...props} />,
};
## 这是二级标题
鼠标悬停在标题上,会出现 # 锚点链接。
### 这是三级标题
所有 h2 和 h3 都自动应用了自定义样式。

实战:给外部链接加图标

创建 ExternalLink.astro

---
interface Props {
href?: string;
}
const { href } = Astro.props;
const isExternal = href?.startsWith('http');
---
<a href={href} target={isExternal ? '_blank' : undefined} rel={isExternal ? 'noopener noreferrer' : undefined}>
<slot />
{isExternal && <span class="ml-1 text-xs">↗</span>}
</a>

映射使用:

import ExternalLink from '@/components/ExternalLink.astro';
export const components = {
a: ExternalLink,
};
[这是内部链接](/about)
[这是外部链接](https://example.com) ← 会自动加 ↗ 图标

全局配置映射(高级)

如果你想让所有 MDX 文件都用同一套组件映射,可以在 astro.config.mjs 里配置。不过这个需要自定义 MDX 插件,稍微复杂一点,我一般是在单个文件里配置就够了。

数学公式和图表集成#

集成 KaTeX 展示数学公式#

如果你写算法、数学或数据科学类的文章,肯定需要展示公式。KaTeX 是目前最好的选择,比 MathJax 快很多,而且支持服务端渲染。

安装 KaTeX

需要安装三个包:

npm install remark-math rehype-katex katex
  • remark-math:解析 LaTeX 语法
  • rehype-katex:渲染公式为 HTML
  • katex:KaTeX 核心库

配置 Astro

打开 astro.config.mjs,添加这两个插件:

import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
import remarkMath from 'remark-math';
import rehypeKatex from 'rehype-katex';
export default defineConfig({
integrations: [mdx()],
markdown: {
remarkPlugins: [remarkMath],
rehypePlugins: [rehypeKatex],
},
});

引入 KaTeX 样式

这一步很重要,不然公式渲染不出来。在你的布局文件(如 src/layouts/MarkdownLayout.astro)的 <head> 里加上:

<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css"
crossorigin="anonymous"
/>

在文章中使用公式

配置好后,就可以在 Markdown/MDX 里写公式了。

行内公式(用单个 $ 包裹):

质能方程:$E = mc^2$
二次方程的解:$x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$

块级公式(用双 $$ 包裹):

$$
\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}
$$
$$
\sum_{i=1}^{n} i = \frac{n(n+1)}{2}
$$

常见问题:公式不显示

如果公式不显示或样式不对,检查这几点:

  1. KaTeX CSS 是否正确引入(F12 看 Network 面板)
  2. rehype-katex 的版本是否兼容(试试降到 6.x 版本)
  3. 公式语法是否正确(去 KaTeX 支持列表 确认)

集成 Mermaid 绘制流程图和图表#

Mermaid 可以用代码画流程图、时序图、甘特图等,特别适合技术文档。

三种集成方案对比

社区有几种 Mermaid 集成方案,我简单说说区别:

方案渲染方式SEO配置难度推荐指数
rehype-mermaid服务端⭐⭐⭐⭐⭐
astro-diagram服务端⭐⭐⭐⭐
astro-mermaid客户端⭐⭐⭐

我推荐 rehype-mermaid,服务端渲染,SEO 友好,生成的是静态 SVG。

安装 rehype-mermaid

npm install rehype-mermaid

配置

astro.config.mjs 里添加:

import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
import rehypeMermaid from 'rehype-mermaid';
export default defineConfig({
integrations: [mdx()],
markdown: {
rehypePlugins: [
[rehypeMermaid, { strategy: 'img-svg' }]
],
},
});

strategy: 'img-svg' 表示生成 SVG 图片,这是最稳定的方案。

在文章中画图

mermaid 代码块就行:

流程图示例

```mermaid
graph TD
A[开始] --> B{是否安装MDX}
B -->|是| C[配置代码高亮]
B -->|否| D[安装MDX]
D --> C
C --> E[完成]
```

时序图示例

```mermaid
sequenceDiagram
用户->>浏览器: 访问页面
浏览器->>服务器: 请求HTML
服务器->>浏览器: 返回渲染后的页面
浏览器->>用户: 显示内容
```

构建时生成

运行 npm run build 时,Mermaid 图表会在构建阶段生成为 SVG,最终页面里是静态图片,加载速度快,也不需要客户端 JavaScript。

注意事项

如果构建时报错”找不到 Puppeteer”,可能需要额外配置。试试安装 playwright:

npm install -D playwright

或者换用 astro-diagram 方案,它内置了浏览器环境。

高级技巧和最佳实践#

Content Collections 的 MDX 优化#

如果你用 Astro 的 Content Collections 管理博客文章(强烈推荐),MDX 文件可以获得更好的类型支持和开发体验。

Content Collections 是什么?

简单说,就是把文章放在 src/content/ 目录下,Astro 会自动识别、验证 frontmatter,并提供类型安全的 API 来读取内容。

配置 Content Collections

src/content/config.ts 定义你的集合:

import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
type: 'content', // 表示这是内容文件(Markdown/MDX)
schema: z.object({
title: z.string(),
description: z.string(),
pubDate: z.date(),
tags: z.array(z.string()).optional(),
draft: z.boolean().default(false),
}),
});
export const collections = { blog };

在 MDX 中使用

MDX 文件的 frontmatter 会被自动验证:

---
title: Astro MDX 进阶教程
description: 学习 MDX 的高级用法
pubDate: 2025-12-02
tags: [Astro, MDX, 教程]
---
import Alert from '@/components/Alert.astro';
# {frontmatter.title}
<Alert type="info">
发布日期:{frontmatter.pubDate.toLocaleDateString()}
</Alert>

自动生成目录

Content Collections 提供了 getHeadings() 方法,可以获取文章的所有标题,用来生成目录:

---
import { getEntry } from 'astro:content';
const entry = await getEntry('blog', 'my-mdx-article');
const { Content, headings } = await entry.render();
---
<aside>
<h2>目录</h2>
<ul>
{headings.map(h => (
<li style={`margin-left: ${(h.depth - 1) * 1}rem`}>
<a href={`#${h.slug}`}>{h.text}</a>
</li>
))}
</ul>
</aside>
<article>
<Content />
</article>

这个功能在写长文时特别实用,读者可以快速跳转到感兴趣的章节。

性能优化和常见陷阱#

MDX 很强大,但用不好也会拖慢网站。

避免过度使用客户端组件

MDX 里可以用 React/Vue 组件,但别忘了加 client:* 指令。如果不加,组件只会服务端渲染,交互功能不生效;如果滥用 client:load,会增加大量 JavaScript,拖慢页面加载。

我的建议:

  • 静态内容用 Astro 组件(如 Alert、Callout)
  • 需要交互的用 client:visible(可见时才加载)或 client:idle(空闲时加载)
  • 除非必要,不用 client:load

图片优化

在 MDX 里插入图片,别直接用 <img>,用 Astro 的 Image 组件:

---
title: 我的文章
---
import { Image } from 'astro:assets';
import cover from './cover.jpg';
<Image src={cover} alt="封面图" width={800} height={600} />

Astro 会自动优化图片(压缩、生成 WebP、懒加载等),性能好很多。

MDX 的 optimize 选项

如果你的站点有很多 MDX 文件,构建很慢,可以试试开启 optimize 选项:

export default defineConfig({
integrations: [
mdx({
optimize: true,
}),
],
});

这个选项会通过内部的 rehype 插件优化 MDX 输出,加快构建速度。不过可能会改变生成的 HTML 结构,用之前先测试一下。

常见错误和解决方案

错误原因解决方案
MDX 组件不显示忘了导入组件检查 import 语句
交互组件不工作缺少 client: 指令加上 client:load
代码高亮不生效Shiki 配置错误检查 astro.config.mjs
数学公式不渲染KaTeX CSS 未引入在 layout 里加 CSS 链接
构建很慢MDX 文件太多开启 optimize 选项

我的踩坑记录#

第一次用 MDX 时最常遇到的问题是组件不显示。折腾了半天才发现,在 .mdx 文件里导入组件要放在 frontmatter 之后,不能放在前面。这个错误我犯了两次,后来才记住。

配置 Shiki Transformers 也花了不少时间。按照文档安装了 @shikijs/transformers,结果导入时一直报错。后来发现是版本问题,需要安装 shiki 本身而不是只用 transformers 包。改完之后 transformers 就能正常工作了。

KaTeX 的样式引入也踩过坑。一开始把 CSS 链接放在了组件里,结果页面切换时样式就丢失了。后来把 CSS 链接移到全局 layout 文件的 <head> 里,问题才解决。

Mermaid 图表在构建时一直失败,提示找不到浏览器环境。试了好几个方案,最后换成了 astro-diagram,它内置了 headless 浏览器,配置简单很多。现在写架构图、流程图都用 Mermaid,比画图工具快多了。

Content Collections 的 schema 定义一开始没太在意,写了篇文章 frontmatter 字段写错了,构建时才发现。后来慢慢习惯了,加上 schema 后写文章时 IDE 会给类型提示,反而减少了很多错误。

MDX 确实让写技术博客灵活了很多。现在写代码教程会加代码高亮标注,写算法文章会加数学公式,写架构设计会画流程图。读者反馈说看着清晰多了,我自己写起来也顺手。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!

赞助
Astro Markdown 进阶技巧:7个让博客变专业的实用方法
https://blog.moewah.com/posts/astro-mdx-advanced-tips-blog-professional-upgrade/
作者
GoWah
发布于
2025-07-12
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
GoWah
Hello, I'm GoWah.
分类
标签
站点统计
文章
160
分类
9
标签
350
总字数
301,106
运行时长
0
最后活动
0 天前

目录