news 2026/9/21 23:16:43

@mdx-js/vue 完全指南:在 Vue 项目中用 Context 为 MDX 注入组件

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
@mdx-js/vue 完全指南:在 Vue 项目中用 Context 为 MDX 注入组件

@mdx-js/vue 完全指南:在 Vue 项目中用 Context 为 MDX 注入组件

【免费下载链接】mdxMarkdown for the component era项目地址: https://gitcode.com/gh_mirrors/md/mdx

@mdx-js/vue是 MDX 官方生态中面向 Vue 的 context 组件提供器,它基于 Vue 的provide/inject机制,让嵌套的 MDX 文件无需层层手动传递components属性即可共享自定义组件映射。读完本文,你将掌握@mdx-js/vue的安装方式、MDXProvideruseMDXComponents两个核心 API 的用法、providerImportSource编译选项的底层实现原理,以及如何在 Vue 3 项目中正确配置并验证这套组件注入体系。

什么是 @mdx-js/vue

@mdx-js/vue是一个基于context(上下文)的组件提供器,作用是把 Vue 与 MDX 结合起来。它对外只提供两个标识符:MDXProvider(Vue 组件)和useMDXComponents(组合式函数),且没有默认导出——这一点在 packages/vue/test/index.js 的公开 API 测试中有明确验证:

assert.deepEqual(Object.keys(await import('@mdx-js/vue')).sort(), [ 'MDXProvider', 'useMDXComponents' ])

整个包的实际实现非常精简,核心代码全部位于 packages/vue/lib/index.js,对外入口 packages/vue/index.js 仅做了一行再导出:

export {MDXProvider, useMDXComponents} from './lib/index.js'

什么时候需要它:为什么官方说"不是必需"

官方文档给出的第一条重要提示是:这个包并不是 MDX 在 Vue 中运行的必要条件。单层使用时,直接给 MDX 组件传components属性即可完成组件替换,引入 Provider 只会徒增包体。

但在嵌套 MDX 文件(在 MDX 中再 import 其他 MDX/Markdown 文件)的场景下,手动透传会变得繁琐——你不得不在每个子组件上写<License components={props.components} />这样的重复代码。针对这一痛点,使用 MDX 指南中给出了三步设置方案:

  1. 根据所用框架安装@mdx-js/react@mdx-js/preact@mdx-js/vue
  2. 在 MDX 编译器的ProcessorOptions中把providerImportSource配置为对应包名(Vue 场景即'@mdx-js/vue');
  3. 从该包导入MDXProvider,用它包裹最顶层的 MDX 内容组件并传入components

Context 的职责正如官方文档所述:提供一种在组件树中传递数据、而无需在每一层手动透传 props 的方式。这正是MDXProvider存在的价值。

安装

@mdx-js/vueESM only的包,不支持 CommonJS。根据 packages/vue/package.json 的声明:

  • 当前版本为3.1.1"type": "module""exports": "./index.js"
  • peerDependencies要求vue >= 3.0.0(依赖的是 Vue 3 的组合式 API 与 Fragment 渲染);
  • 运行时依赖仅@types/mdx ^2.0.0(用于提供MDXComponents类型),并标记"sideEffects": false,方便打包器摇树优化。

Node.js(版本 16+)配合 npm 安装:

npm install @mdx-js/vue

在 Deno 中使用 esm.sh:

import {MDXProvider} from 'https://esm.sh/@mdx-js/vue@3'

在浏览器中直接以模块方式使用 esm.sh:

<script type="module"> import {MDXProvider} from 'https://esm.sh/@mdx-js/vue@3?bundle' </script>

?bundle参数用于让 esm.sh 返回一个适合浏览器直接执行的打包产物。

基本使用

下面是一个完整的 Vue 3 使用示例(摘自官方文档):假设你通过@mdx-js/esbuild@mdx-js/loader@mdx-js/node-loader@mdx-js/rollup等集成工具把./post.mdx编译为 JS,并且编译配置中设置了options.providerImportSource: '@mdx-js/vue'

import {MDXProvider} from '@mdx-js/vue' import {createApp} from 'vue' import Post from './post.mdx' // ^-- 假设已用某个集成工具将 MDX 编译为 JS,且配置了 // `options.providerImportSource: '@mdx-js/vue'` createApp({ data() { return {components: {h1: 'h2'}} }, template: '<MDXProvider v-bind:components="components"><Post /></MDXProvider>', components: {MDXProvider, Post} })

注意v-bind:components="components"components数据在data()中定义,MDX 编译产物中的# Hello world会在渲染时通过 Provider 上下文找到h1的替代组件,最终被渲染成<h2>

官方特别提醒:你完全可以不用MDXProvider,直接把components作为属性传给 MDX 组件。对于单个 MDX 文件,更简洁的等价写法是:

-createApp({ - data() { - return {components: {h1: 'h2'}} - }, - template: '<MDXProvider v-bind:components="components"><Post /></MDXProvider>', - components: {MDXProvider, Post} -}) +createApp(Post, {components: {h1: 'h2'}})

如何开始使用 MDX 与 Vue,可参考入门指南;Provider 的完整设计动机与适用场景,可参考使用 MDX 指南中的 MDX provider 章节。

API 详解

本包导出MDXProvideruseMDXComponents两个标识符,没有默认导出。

MDXProvider(properties?)

MDX 上下文的提供器,类型为 Vue 的Component。它接收一个可选的components属性(MDXComponents类型),并在渲染时把传入的组件通过 Vue 的provide注入到整棵子树中。

useMDXComponents(components?)

从 MDX Context 中读取当前组件映射。

  • 参数:没有参数(文档标题中的(components?)仅为历史遗留写法,源码签名useMDXComponents()不接受任何入参);
  • 返回值:当前的组件映射,类型为MDXComponents(该类型来自mdx/types.js,由@types/mdx提供)。

Props

MDXProvider的 TypeScript 配置类型,包含一个字段:

字段类型说明
componentsMDXComponents(可选)需要注入的额外组件

工作原理:provide/inject 与 providerImportSource

从源码层面看,MDXProvider的实现极简(见 packages/vue/lib/index.js):

import {Fragment, createVNode, inject, provide} from 'vue' export const MDXProvider = { name: 'MDXProvider', props: { components: { default() { return {} }, type: Object } }, setup(properties) { provide('$mdxComponents', properties.components) }, render() { return createVNode( Fragment, undefined, this.$slots.default ? this.$slots.default() : [] ) } } export function useMDXComponents() { return inject('$mdxComponents', {}) }

几个值得注意的实现细节:

  1. 上下文键setup中用provide('$mdxComponents', ...)注入,useMDXComponentsinject('$mdxComponents', {})读取,默认值为空对象,保证未提供 Provider 时也能安全运行。
  2. 透传渲染render()返回一个Fragment包裹的默认插槽内容,因此MDXProvider本身不产生多余 DOM 节点,可以任意包裹 MDX 内容组件。
  3. 懒读取useMDXComponents只有在被调用时才从上下文中取值,这为 MDX 编译产物的"运行时按需注入组件"提供了钩子。

编译侧的配合机制位于 packages/mdx/lib/plugin/recma-jsx-rewrite.js。当providerImportSource被设置时,该插件会在编译产物中:

  • useMDXComponents为导入名、_provideComponents为本地别名,从providerImportSource指向的模块插入 import 语句(对应源码中createImportProvider函数);
  • _createMdxContent函数内调用_provideComponents()获取上下文中的组件,再与props.components及局部定义组件做合并(对应parameters.push({... _provideComponents ...})及后续的ObjectExpression合并逻辑);
  • 合并结果赋给_components,并从中解构出 MDX 中实际用到的组件名(如const {MyComponent, wrapper: MDXLayout} = _components)。

也就是说,providerImportSource的值本身"是什么"并不重要,关键是该模块必须导出一个名为useMDXComponents的标识符——编译插件只认这个名字。@mdx-js/vue恰好满足这一约定,因此可以直接作为该选项的值。

如果不想走编译期注入,也可以使用@mdx-js/mdxevaluate在运行时编译并执行 MDX:配置providerImportSource: '#'并在run的 options 中传入useMDXComponents(见 packages/mdx/lib/util/resolve-evaluate-options.js)。需要说明的是,run/runSync内部通过new Function求值执行编译产物(见 packages/mdx/lib/run.js),官方明确标注了"这会 eval JavaScript"的风险警示,因此只应运行可信内容。

测试验证

packages/vue/test/index.js 用 Node 内置的node:test框架对本包做了全面覆盖,核心断言包括:

  • 公开 API 仅导出MDXProvideruseMDXComponents两个标识符;
  • 通过compile+run评估 MDX(# hi<h1>hi</h1>),验证 MDX 内容本身能被 Vue 正确渲染;
  • 支持在 MDX 内定义 Vue 组件(export const A = {render() {...}}后以<A />使用);
  • 支持直接传components{components: {h1: 'h2'}}渲染出<h2>hi</h2>);
  • 支持MDXProvider包裹(含带components、不带components、无插槽内容三种形态,无内容时渲染为空字符串'')。

测试通过@vue/server-rendererrenderToString得到 HTML 字符串后去除 SSR 注释再做断言,说明该包同时适用于客户端渲染与服务端渲染场景。

TypeScript 类型支持

@mdx-js/vue完全使用 TypeScript 编写类型,并额外导出Props类型。要获得完整类型提示,需要确保 TypeScript 的JSX命名空间已正确配置——通常通过安装并引入框架自身的类型(Vue 场景即vue包自带类型)来完成。编译期providerImportSource的类型校验与MDXComponents的定义由@types/mdx提供,这也是该包唯一的运行时依赖。

兼容性

unified 社区维护的项目遵循"与仍在维护的 Node.js 版本保持兼容"的策略;每发布一个 major 版本,就会放弃对已停止维护的 Node 版本的支持。因此当前发布线@mdx-js/vue@^3的目标是兼容Node.js 16+,并保持 ESM only 的模块形态。安装或升级前请确认你的运行时满足上述前提。

安全说明

关于 MDX 内容与组件注入的安全边界,官方在安全章节中有统一说明。结合本包的实际行为,需要特别记住:MDX 支持嵌入 JSX 表达式和组件,配合run/runSync这类求值机制时,只应编译和执行可信来源的内容,否则可能带来任意代码执行风险。

许可证

@mdx-js/vue以 MIT 协议发布,版权归 Compositor 与 Vercel 所有。

【免费下载链接】mdxMarkdown for the component era项目地址: https://gitcode.com/gh_mirrors/md/mdx

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 22:42:39

从网页对话到AI编程工作台:本地模型、模型网关与提示词实战

最近大半年&#xff0c;我把自己的开发环境逐步从“编辑器 浏览器问AI”切换成了一整套真正意义上的 AI 编程工作台。这里说的“工作台”不是某个软件&#xff0c;而是一套组合&#xff1a;终端、编辑器、本地模型、云端 API、提示词模板和自动化脚本协同工作&#xff0c;目的…

作者头像 李华
网站建设 2026/9/20 22:38:56

ChatTTS-ui 音色定制 3 种方式实操:固定音色、种子值与 pt 文件转换

ChatTTS-ui 音色定制 3 种方式实操&#xff1a;固定音色、种子值与 pt 文件转换 【免费下载链接】ChatTTS-ui 一个简单的本地网页界面&#xff0c;使用ChatTTS将文字合成为语音&#xff0c;同时支持对外提供API接口。A simple native web interface that uses ChatTTS to synth…

作者头像 李华