Astro MDX 实战:用 with-mdx 示例掌握 .mdx 页面、JSX 表达式与交互组件
2026/9/7 10:40:25 网站建设 项目流程

Astro MDX 实战:用 with-mdx 示例掌握 .mdx 页面、JSX 表达式与交互组件

【免费下载链接】astroThe web framework for content-driven websites. ⭐️ Star to support our work!项目地址: https://gitcode.com/GitHub_Trending/as/astro

本文基于 Astro 仓库中的with-mdx官方示例,讲解如何使用@astrojs/mdx集成把.mdx文件作为页面:从创建项目、配置集成,到在 MDX 中使用 JSX 表达式、客户端岛屿组件与自定义标题组件,并结合@astrojs/mdx的源码解析其默认行为与可配置项,帮助读者完整掌握在 Astro 中编写内容驱动页面的 MDX 工作流。

使用模板快速创建 MDX 项目

examples/with-mdx示例展示了如何使用@astrojs/mdx集成以 MDX)给出的标准创建命令是:

npm create astro@latest -- --template with-mdx

也可以使用npx create-astro交互式创建时选择with-mdx模板。创建后的项目骨架与仓库中的示例保持一致,最小结构如下:

with-mdx/ ├─ public/ │ └─ favicon.svg / favicon.ico ├─ src/ │ ├─ components/ │ │ ├─ Counter.jsx # Preact 客户端组件 │ │ └─ Title.astro # Astro 组件,用作自定义 <h1> │ └─ pages/ │ └─ index.mdx # MDX 页面(路由 /) ├─ astro.config.mjs ├─ package.json └─ tsconfig.json

项目配置:集成声明与依赖

astro.config.mjs

examples/with-mdx/astro.config.mjs 是本项目唯一的配置文件,内容非常精炼:

// @ts-check import mdx from '@astrojs/mdx'; import preact from '@astrojs/preact'; import { defineConfig } from 'astro/config'; // https://astro.build/config export default defineConfig({ integrations: [mdx(), preact()], });

两个集成各司其职:

  • mdx():注册.mdx作为页面扩展名与内容条目类型,使src/pages/*.mdx可以直接作为路由(index.mdx对应/);
  • preact():提供 JS 渲染器(JSX runtime),这是 MDX 中嵌入 React/Preact 等框架组件所必需的——mdx()集成自身在 packages/integrations/mdx/src/index.ts 中还会注册一个名为astro:jsx的服务端渲染入口,配合渲染器完成 MDX 中 JSX 的服务端执行。

package.json 依赖与 Node 版本

examples/with-mdx/package.json 声明了如下关键信息,可作为本地项目的版本基线:

{ "engines": { "node": ">=22.12.0" }, "scripts": { "dev": "astro dev", "build": "astro build", "preview": "astro preview", "astro": "astro" }, "dependencies": { "@astrojs/mdx": "^8.0.0", "@astrojs/preact": "^6.0.5", "astro": "^7.2.10", "preact": "^10.28.4" } }

其中@astrojs/mdx@astrojs/preactpreactastro四个依赖分别对应 MDX 集成、Preact 集成、Preact 运行时与 Astro 框架本体。日常开发使用npm run dev启动开发服务器,npm run build构建静态站点,npm run preview本地预览构建产物。

tsconfig.json

examples/with-mdx/tsconfig.json 继承 Astro 官方严格配置,并纳入生成类型:

{ "extends": "astro/tsconfigs/strict", "include": [".astro/types.d.ts", "**/*"], "exclude": ["dist"] }

核心页面:index.mdx 的完整解析

examples/with-mdx/src/pages/index.mdx 是本示例的核心文件,几乎涵盖了 MDX 在 Astro 中的所有典型用法:

import Counter from '../components/Counter.jsx'; import Title from '../components/Title.astro'; export const components = { h1: Title }; export const authors = [ { name: 'Jane', email: 'hi@jane.com' }, { name: 'John', twitter: '@john2002' }, ]; export const published = new Date('2022-02-01'); # Hello world! Written by: {new Intl.ListFormat('en').format(authors.map(d => d.name))}. Published on: {new Intl.DateTimeFormat('en', {dateStyle: 'long'}).format(published)}. <Counter client:idle>This is a **counter**!</Counter> ## Syntax highlighting ```astro --- const weSupportAstro = true; --- <h1>Hey, what theme is that? Looks nice!</h1>
逐段拆解如下。 ### 1. 导入组件与在 Markdown 中引用 JSX MDX 文件就是一个 ES 模块,因此可以直接 `import` 任意组件(JSX 组件或 Astro 组件),并在正文中像写标签一样使用。文件顶部的两个 `import` 引入了 Preact 的 [Counter](https://link.gitcode.com/i/ba3d3e22b23fdda2b9e73ef8156934dd) 组件和 Astro 的 [Title](https://link.gitcode.com/i/be3a70051b553d18a8ba357c2ce4cd15) 组件。 ### 2. 导出 frontmatter 数据并在正文中消费 `export const` 声明的变量会进入该文件的 frontmatter(可被 `getStaticPaths`、Content Collections 等机制读取),同时也可以在 MDX 正文中以 `{表达式}` 的形式直接使用。示例中: - `authors` 数组通过 `Intl.ListFormat` 格式化为英文作者列表; - `published` 日期通过 `Intl.DateTimeFormat` 渲染为长日期格式。 这正是 MDX 相对纯 Markdown 的核心优势:正文即代码,任意 JS 表达式都能内联求值。 ### 3. 覆盖默认 HTML 组件:`export const components` `export const components = { h1: Title }` 表示该 MDX 文档中所有的 `<h1>` 元素都将被替换为 `Title` 组件渲染。对应的 [Title.astro](https://link.gitcode.com/i/be3a70051b553d18a8ba357c2ce4cd15) 实现: ```astro <h1><slot /></h1> <style> h1 { color: red; } </style>

它用<slot>接收被覆盖的<h1>文本,并借助 Astro 的样式作用域能力把标题染红。这种方式等价于"文档级组件重写":不改变 Markdown 源码(仍写# 标题),却可以在渲染层定制输出。

4. 在 MDX 中放置客户端岛屿

<Counter client:idle>This is a **counter**!</Counter>

client:idle是 Astro 的客户端指令,指示该组件在浏览器空闲时水合为客户端组件。Counter.jsx是一个使用 Preact hooks 的标准客户端组件:

import { useState } from 'preact/hooks'; export default function Counter({ children }) { const [count, setCount] = useState(0); const add = () => setCount((i) => i + 1); const subtract = () => setCount((i) => i - 1); return ( <> <div class="counter"> <button onClick={subtract}>-</button> <pre>{count}</pre> <button onClick={add}>+</button> </div> <div class="counter-message">{children}</div> </> ); }

注意两点:其一,传给Counter的子内容是 Markdown 的**counter**加粗文本,说明 MDX 中 Markdown 语法与 JSX 标签可以自由混排;其二,组件水合依赖 Preact 渲染器,这也是配置中必须同时引入preact()集成与preact依赖的原因。

5. 开箱即用的代码高亮

正文中的```astro围栏代码块会被 Shiki 高亮渲染——MDX 集成的syntaxHighlight默认开启(基于 Astro 共享的 markdown 配置),示例页面默认使用 Shiki 的默认主题。若需自定义主题或语言别名,见下一节的配置说明。

@astrojs/mdx 集成选项与源码级行为

以上述示例为基线,mdx()还接受一组可选项。从 packages/integrations/mdx/src/index.ts 中的MdxOptions类型定义可以确认当前支持的配置面:

// 简化后的选项形态(摘自 MdxOptions 类型定义) mdx({ syntaxHighlight, // Shiki 代码高亮配置,继承 config.markdown shikiConfig, // Shiki 主题等配置 gfm, // GitHub Flavored Markdown,已弃用,建议走 processor smartypants, // 智能标点,已弃用,建议走 processor extendMarkdownConfig, // 是否继承 markdown 全局配置 processor, // 覆盖 .mdx 文件的 markdown 处理器 optimize, // MDX 静态优化,false | { ignoreElementNames } })

结合源码(packages/integrations/mdx/src/index.ts)可以确认几个关键默认行为:

  1. extendMarkdownConfig默认为true.mdx文件默认继承astro.config中的markdown全局配置(包括syntaxHighlightshikiConfig),所以示例项目无需任何额外配置即获得代码高亮。若设为false,则.mdx使用一套全新的satteri()处理器,不与.md共享配置;
  2. processor可覆盖.mdx的处理管线:可以为.mdx单独指定一个MarkdownProcessor(例如从@astrojs/markdown-remarkunified()创建),使其与.md文件走不同的 remark/rehype 管线;
  3. optimize默认为false:这是 MDX 的静态优化开关(支持ignoreElementNames选项),关闭时行为最直观可预期;
  4. 遗留插件选项已弃用remarkPluginsrehypePluginsremarkRehyperecmaPlugins在 源码 中被标记为LEGACY_PLUGIN_OPTIONS,传入时会在astro:config:done钩子中打印弃用警告(见warnDeprecatedMdxPluginOptions)。官方建议的替代做法是把插件传给@astrojs/markdown-remarkunified({...}),并设置为markdown.processor——MDX 会自动继承。且当.mdx使用的处理器不是unified时(例如默认的 satteri),这些插件会被忽略并额外警告(见warnLegacyMdxPluginOptionsIgnored)。

此外,集成在astro:config:setup钩子中完成的注册工作(源码)解释了示例项目为何"零额外配置"即可工作:

  • addPageExtension('.mdx'):让src/pages/*.mdx参与路由(index.mdx/);
  • addContentEntryType({ extensions: ['.mdx'], ... }):注册.mdx为内容条目类型,getEntryInfo通过safeParseFrontmatter解析 frontmatter,使.mdx文件可被 Content Collections 消费;
  • 由于 MDX 可以import脚本与样式,注册时设置了handlePropagation: true,对所有 MDX 文件进行 script/style 传播检查。

小结

  • npm create astro@latest -- --template with-mdx创建项目,在 astro.config.mjs 中注册mdx()与一个 JSX 渲染器(示例使用preact());
  • src/pages/*.mdx即页面路由,文件本身是 ES 模块:可import组件、export const导出 frontmatter 数据并在正文以{表达式}内联使用;
  • export const components = { h1: Title }覆盖文档级 HTML 组件渲染,是"不改源码、定制输出"的轻量方案;
  • 通过client:idle等客户端指令在 MDX 中放置 Preact/React/Svelte 等框架组件,实现内容页面 + 交互岛屿的混合架构;
  • 代码高亮开箱即用(Shiki),需要深度定制时阅读@astrojs/mdxMdxOptionsextendMarkdownConfigprocessoroptimize与已弃用的遗留插件选项,均可在 packages/integrations/mdx/src/index.ts 中核对当前实现。

【免费下载链接】astroThe web framework for content-driven websites. ⭐️ Star to support our work!项目地址: https://gitcode.com/GitHub_Trending/as/astro

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询