@diplodoc/mdx-extension

中文文档
1.10.1发布于 2026/06/17TypeScriptESM + CJS近 30 天下载 6632

npm version License

中文使用文档
文档目录41 节
  1. 安装
  2. 特征
  3. 使用量
  4. 基本设置
  5. 使用默认组件倒置
  6. 启用 MDX 输入验证
  7. 客户端渲染( CSR)
  8. 服务器端渲染( SSR)
  9. 收集插件
  10. 同步收集插件
  11. 一个同步收集插件
  12. 占位符渲染器
  13. 如何运作
  14. 使用量
  15. 同步占位符渲染
  16. Raw MDX 内容插件
  17. 如何运作
  18. 使用量
  19. 与 Diplodoc 变形合并
  20. API 参考
  21. mdxPlugin(options?: { render?: MDXRenderer })
  22. useMdx(options: UseMdxProps): React.Fragment
  23. useMdxSsr(options: UseMdxSsrProps): React.Fragment
  24. getRenderer(options: GetRenderProps)
  25. getSsrRenderer(options: GetSsrRendererProps)
  26. getAsyncSsrRenderer(options: GetAsyncSsrRendererProps)
  27. getMdxCollectPlugin(options: Options)
  28. getAsyncMdxCollectPlugin(options: AsyncOptions)
  29. 州管理背景
  30. 组件增强器
  31. 语法示例
  32. 明确的 MDX 标记
  33. JSX 碎片
  34. 直接组件使用
  35. 高级特性
  36. 安全部门改革国家管理
  37. 与初始道具同步 SSR
  38. 纯元件
  39. 同步组件加载
  40. 汇编选项
  41. 许可证

@diplodoc/mdx-扩展

npm version License

Diplodoc的标记下变压器的MDX扩展可以将MDX/JSX组件嵌入标记下的内容.

安装

npm install @diplodoc/mdx-extension
# or
yarn add @diplodoc/mdx-extension

特征

  • 无缝地将JSX/MDX组件纳入下调内容
  • 支持客户端(CSR)和服务器端(SSR)渲染
  • 跟踪背景变化的背景支持
  • 多个语法选项 :
    • 明确 <MDX>...</MDX> 标记
    • JSX碎片 <>...</>
    • 直接反应组件使用 <Component />
  • MDX 输入验证的内置安全
  • 对高级组件安装的门户支持 withPortal
  • 通过同步组件加载支持 idMdxComponentLoader
  • 缺失 MDX 引用的默认组件倒计时 recmaDefaultComponent

使用量

基本设置

首先,增加一个 mdxPlugin() 到您的 Diplodoc 变换插件 :

import transform from '@diplodoc/transform';
import DefaultPlugins from '@diplodoc/transform/lib/plugins';
import {mdxPlugin} from '@diplodoc/mdx-extension';

const result = transform(markdownContent, {
  plugins: [...DefaultPlugins, mdxPlugin()],
});

使用默认组件倒置

这个 recmaDefaultComponent 插件为缺失的 MDX 组件引用提供优雅回落. 它不扔出错误,而是重定向到可配置的默认组件.

import {mdxPlugin, recmaDefaultComponent} from '@diplodoc/mdx-extension';

const result = transform(markdownContent, {
  plugins: [
    ...DefaultPlugins,
    mdxPlugin({
      compileOptions: {
        recmaPlugins: [recmaDefaultComponent({componentName: 'DefaultComponent'})],
      },
    }),
  ],
});

示例默认组件 :

const Components = {
  DefaultComponent: ({tagName, ...props}) => (
    <div style={{border: '1px dashed red'}}>Missing component: {tagName}</div>
  ),
};

启用 MDX 输入验证

这个 validateMdx 插件为 矩形插件 (Rhype Compatible MDAST to JavaScript AST 编译器)通过分析生成的抽象语法树(AST)来验证MDX内容的安全性. 它通过限制允许的JavaScript构造和模式来阻止潜在不安全代码的执行.

启用 MDX 输入的安全验证 :

import {mdxPlugin, validateMdx} from '@diplodoc/mdx-extension';

const result = transform(markdownContent, {
  plugins: [
    ...DefaultPlugins,
    mdxPlugin({
      compileOptions: {
        recmaPlugins: [validateMdx],
      },
    }),
  ],
});

插件验证

这个 validateMdx 插件通过 :

  1. 限制 JSX 道具值 只允许:

    • 字数(字符串、数字、布尔)
    • 标识符
    • 阵列表达式( 有有效的元素)
    • 对象表达式( 具有有效属性)
    • 二进制表达式( 有有效的操作)
    • JSX的具体呼吁_jsxs, (中文(简体) ), _jsx(中文(简体) )
  2. 封锁危险道具 包括:

    • dangerouslySetInnerHTML
    • ref
    • 事件处理器(从 on[A-Z](中文(简体) )
    • 在不安全的 URL 协议中 href, (中文(简体) ), src, (中文(简体) ), action 道具(块) javascript: 财务报告和审定财务报表 data:text/html(中文(简体) )
  3. 限制组件类型 仅改为:

    • 已建MDX组件(_Fragment, (中文(简体) ), MDXLayout, (中文(简体) ), _createMdxContent(中文(简体) )
    • 来自 _components 对象
    • 文体组件名称
  4. 取消不安全的 JavaScript 构造数字 :

    • 函数声明(特定 MDX 函数除外)
    • 可变声明(具体模式除外)
    • 成员表达式(具体模式除外)
    • 调用表达式( 特定函数除外)
    • 新表达式( 只有 Error 允许)
    • 散开元素( 仅特定模式)
    • 逻辑表达式( 只有特定模式)
    • Async/await、出产、转让、导入和函数表达式
  5. 执行深度限制 (最大深度50)防止过于复杂的AST

为什么使用这个插件?

  • 警卫: 防止在 MDX 内容中执行任意 JavaScript 代码
  • 服务器侧保护: 屏蔽安全代码, 可以在 SSR 期间执行
  • 受控制环境:确保只允许批准的模式
  • 早期错误检测: 在执行前抛出可疑模式的验证错误

校验错误

当插件检测出无效的图案时,它会抛出描述性错误,例如:

  • 不可允许“ 危险” 的组件道具
  • 这里不允许“ 组件标签类型... ”
  • "功能宣言在这里是不允许的"
  • "最大深度超过"

客户端渲染( CSR)

import React, {Fragment, useMemo, useRef} from 'react';
import transform from '@diplodoc/transform';
import DefaultPlugins from '@diplodoc/transform/lib/plugins';
import {mdxPlugin, useMdx, isWithMdxArtifacts, validateMdx} from '@diplodoc/mdx-extension';

const Components = {
  CustomComponent: (props) => <div {...props}>Custom</div>,
};

const CONTENT = `
# Markdown Content

<CustomComponent style={{color: 'red'}} />

<MDX>
  <div>This will be rendered as MDX</div>
</MDX>
`;

function App() {
  const ref = useRef(null);

  const {html, mdxArtifacts} = useMemo(() => {
    const {result} = transform(CONTENT, {
      plugins: [
        ...DefaultPlugins,
        mdxPlugin({
          compileOptions: {
            recmaPlugins: [validateMdx],
          },
        }),
      ],
    });

    isWithMdxArtifacts(result);

    return result;
  }, []);

  const portals = useMdx({
    refCtr: ref,
    html,
    components: Components,
    mdxArtifacts,
  });

  return (
    <Fragment>
      <div ref={ref}></div>
      {portals}
    </Fragment>
  );
}

服务器端渲染( SSR)

import React from 'react';
import transform from '@diplodoc/transform';
import DefaultPlugins from '@diplodoc/transform/lib/plugins';
import {mdxPlugin, useMdxSsr, getSsrRenderer, validateMdx} from '@diplodoc/mdx-extension';

const Components = {
  ServerComponent: (props) => <strong {...props}>Server Rendered</strong>,
};

const CONTENT = `
# Server Rendered Content

<ServerComponent />
`;

export async function getServerSideProps() {
  const render = await getSsrRenderer({
    components: Components,
    compileOptions: {
      recmaPlugins: [validateMdx],
    },
  });

  const {result} = transform(CONTENT, {
    plugins: [...DefaultPlugins, mdxPlugin({render})],
  });

  isWithMdxArtifacts(result);

  const {html, mdxArtifacts} = result;

  return {props: {html, mdxArtifacts}};
}

function ServerPage({html, mdxArtifacts}) {
  const ref = useRef(null);

  const portals = useMdxSsr({
    refCtr: ref,
    components: Components,
    mdxArtifacts,
    html,
  });

  const innerHtml = useMemo(() => {
    return {__html: html};
  }, [html]);

  return (
    <Fragment>
      <div ref={ref} dangerouslySetInnerHTML={innerHtml}></div>
      {portals}
    </Fragment>
  );
}

收集插件

收集插件在收集文物的同时提供处理和转换MDX内容的功能. 它同时以同步和同步两种版本出现.

同步收集插件

import {getMdxCollectPlugin} from '@diplodoc/mdx-extension';

const plugin = getMdxCollectPlugin({
  tagNames: ['CustomComponent'], // Optional filter for specific tags
  pureComponents: PURE_COMPONENTS,
  compileOptions: {
    // MDX compilation options
  },
});

const transformedContent = plugin(originalContent);

一个同步收集插件

import {getAsyncMdxCollectPlugin} from '@diplodoc/mdx-extension';

const asyncPlugin = getAsyncMdxCollectPlugin({
  tagNames: ['AsyncComponent'], // Optional filter for specific tags
  pureComponents: PURE_COMPONENTS,
  compileOptions: {
    // MDX compilation options
  },
});

const transformedContent = await asyncPlugin(originalContent);

占位符渲染器

占位器渲染器为MDX内容提供了两相渲染方法. 这对于您需要将解析与执行区分开来, 如延迟渲染, SSR 组件等, 或当您要在多个通道中处理 MDX 内容时, 都是有益的 .

如何运作

  1. 占位符生成: 在初始MDX处理过程中 getPlaceholderRenderer 函数创建带有唯一ID的占位符 HTML 元素,并存储 MDX 的原始内容 mdxArtifacts.idFragment。 。 。 .

  2. 占位符渲染: 后来 createPlaceholderRender 或者说 createAsyncPlaceholderRender 函数处理这些占位符,用实际制作的 HTML 取而代之,并将汇编的代码存储在 idMdx 财务报告和审定财务报表 idTagName 用于客户端水分.

使用量

import {getPlaceholderRenderer, createPlaceholderRender} from '@diplodoc/mdx-extension';

// Create a placeholder renderer
const placeholderRenderer = getPlaceholderRenderer();

// Use it in mdxPlugin
const {result} = transform(content, {
  plugins: [
    ...DefaultPlugins,
    mdxPlugin({
      render: placeholderRenderer,
    }),
  ],
});

// Later, render the placeholders
const render = createPlaceholderRender({
  components: YOUR_COMPONENTS,
  // ... other options
});

const finalHtml = render(result.html, result.mdxArtifacts);

同步占位符渲染

用于同步渲染(例如,组件具有 withInitialProps),使用同步版本:

import {createAsyncPlaceholderRender} from '@diplodoc/mdx-extension';

const asyncRender = createAsyncPlaceholderRender({
  components: YOUR_COMPONENTS,
  // ... other options
});

const finalHtml = await asyncRender(result.html, result.mdxArtifacts);

Raw MDX 内容插件

这个 remarkRawMdxContent 插件是一个注释插件,在指定的组件内取出原始的MDX内容并保存为文本,防止被解析为MDX. 这对需要输出原始MDX/JSX作为文本内容的组件(例如代码示例,文档生成器)有用.

如何运作

插件处理 MDX JSX 元素并针对指定的标签名,取出打开和关闭标签之间的原始文本内容. 然后用一个包含该原始内容的单一文本节点来取而代之,保留了原始格式.

使用量

import {remarkRawMdxContent} from '@diplodoc/mdx-extension';
import {unified} from 'unified';
import remarkParse from 'remark-parse';
import remarkMdx from 'remark-mdx';

const processor = unified()
  .use(remarkParse)
  .use(remarkMdx)
  .use(remarkRawMdxContent, {
    tagNames: ['CodeExample', 'RawContent'], // Specify which tags to process
  });

const tree = processor.parse(`# Example

<CodeExample>
  <Button>Click me</Button>
</CodeExample>`);

const transformedTree = processor.runSync(tree);

与 Diplodoc 变形合并

您可以使用插件作为您的 Diplodoc 变换管道的一部分 :

import transform from '@diplodoc/transform';
import DefaultPlugins from '@diplodoc/transform/lib/plugins';
import {mdxPlugin, remarkRawMdxContent} from '@diplodoc/mdx-extension';

const result = transform(content, {
  plugins: [
    ...DefaultPlugins,
    mdxPlugin({
      compileOptions: {
        remarkPlugins: [[remarkRawMdxContent, {tagNames: ['CodeExample']}]],
      },
    }),
  ],
});

这将确保内部内容 <CodeExample> 标记保存为原始文本,而不是解析为MDX.

API 参考

mdxPlugin(options?: { render?: MDXRenderer })

允许MDX处理的主要插件功能.

选项 :

  • render: 可选的渲染器功能,用于SSD getSsrRenderer
  • tagNames?: string[] - 可选的标签名称阵列以过滤将处理哪些组件

useMdx(options: UseMdxProps): React.Fragment

用于客户端MDX处理的反应钩.

选项 :

  • refCtr: 参考容器元素
  • html: 来自 Diplodoc 转换的 HTML 字符串
  • components: 要使用的反应组件对象
  • mdxArtifacts: MDX 变形器
  • pureComponents?: 不应被水合物(MDX Contiments)组件的可选对象
  • contextList?: 向 MDX 组件提供反射语境阵列
  • idMdxComponentLoader?: 自定义 mdx 组件加载器

useMdxSsr(options: UseMdxSsrProps): React.Fragment

SSR处理过的MDX内容的回放钩.

选项 :

  • refCtr: 参考容器元素
  • html: 来自 Diplodoc 转换的 HTML 字符串
  • components: 要使用的反应组件对象
  • mdxArtifacts: MDX 变形器
  • pureComponents?: 不应被水合物(MDX Contiments)组件的可选对象
  • contextList?: 向 MDX 组件提供反射语境阵列
  • idMdxComponentLoader?: 自定义 mdx 组件加载器

getRenderer(options: GetRenderProps)

为客户端处理创建渲染器功能.

选项 :

  • compileOptions?: MDX 编译选项(参见 MDX 文档(中文(简体) )

getSsrRenderer(options: GetSsrRendererProps)

创建用于服务器侧处理的 SSR 渲染器功能.

选项 :

  • components: 要使用的反应组件对象
  • pureComponents?: 不应被水合物(MDX Contiments)组件的可选对象
  • compileOptions?: MDX 编译选项(参见 MDX 文档(中文(简体) )
  • contextList?: 向 MDX 组件提供反应上下文阵列。 使用 { ctx, initValue } 通过 SSR 初始值的格式

getAsyncSsrRenderer(options: GetAsyncSsrRendererProps)

创建支持的同步 SSR 渲染器 withInitialProps。 。 。 .

选项 :

  • components: 要使用的反应组件对象
  • pureComponents?: 不应被水合物(MDX Contiments)组件的可选对象
  • compileOptions?: MDX 编译选项(参见 MDX 文档(中文(简体) )
  • contextList?: 向 MDX 组件提供反应上下文阵列。 使用 { ctx, initValue } 通过 SSR 初始值的格式

getMdxCollectPlugin(options: Options)

创建用于处理 MDX 内容的同步收集插件.

选项 :

  • tagNames?: string[] - 可选的标签名称阵列以过滤处理
  • pureComponents?: 应跳过客户端水合的组件
  • compileOptions?: MDX 编译选项

getAsyncMdxCollectPlugin(options: AsyncOptions)

创建一个同步收集插件,支持带有初始道具的组件.

选项 :

  • tagNames?: string[] - 可选的标签名称阵列以过滤处理
  • pureComponents?: 应跳过客户端水合的组件
  • compileOptions?: MDX 编译选项

州管理背景

MdxStateCtx: Context<MdxStateCtxValue>

提供对当前 MDX 状态的访问 :

const state = useContext(MdxStateCtx);

MdxSetStateCtx: Context<MdxSetStateCtxValue>

提供状态设置函数( 只在 SSR 期间可用) :

const setState = useContext(MdxSetStateCtx);
// Usage in SSR:
setState?.({key: value});

组件增强器

withInitialProps: WithInitialProps

环绕一个组件,以便在 SSR 期间获取初始道具.

参数:

  • component: 反射组件来包接
  • getInitProps: 接收道具和MDX状态的函数,返回道具(同步或sync)

withPortal: WithPortalProps

通过 React.createPortal 包成组件,允许更灵活的挂起.

参数:

  • component: 反射组件来包接
  • fallback: 可选倒置组件在挂载门户前显示

用法 :

export const COMPONENTS = {
  Tabs: withPortal(TabsLocal, () => <Skeleton />),
};

使用时 withPortal本构成部分将:

  1. 初始后退组件(如果提供)
  2. 准备时创建挂载实际组件的门户
  3. 卸载时清理门户

语法示例

明确的 MDX 标记

<MDX>
  <MyComponent prop="value" />
</MDX>

JSX 碎片

<>

  <div>Fragment content</div>
</>

直接组件使用

<Button onClick={() => console.log('click')}>
Click me
</Button>

高级特性

安全部门改革国家管理

库为服务器-Side渲染(SSR)期间管理状态提供两个上下文提供者:

  • MdxSetStateCtx - 提供更新MDX状态功能的背景。 此功能仅在SSD期间可用(null 在客户端。 如果您使用此上下文设置了组件状态,则会是:

    • 序列化为 data-mdx-state sSR 期间属性
    • 备查 MdxStateCtx 当组件生成时
  • MdxStateCtx - 提供一个访问当前 MDX 状态值的上下文

与初始道具同步 SSR

  • withInitialProps - 能够同步获取安全部门改革数据的更高级组件:

    • 将一个组件与此函数并用时 getAsyncSsrRenderer,则 getInitialProps 函数将调用
    • 接收组件道具和 MDX 状态作为参数
    • 可以返回静态或基于承诺的道具
  • getAsyncSsrRenderer - 一个同步的版本 getSsrRenderer 即:

    • 支持用包起来的组件 withInitialProps
    • 允许在 SSR 期间获取同步数据

示例用法:

const getInitialProps: MDXGetInitialProps<CounterProps> = (props, mdxState) => {
  mdxState.initialValue = 10; // Set initial state
  return props;
};

export const SSR_COMPONENTS = {
  ...COMPONENTS,
  Counter: withInitialProps(Counter, getInitialProps),
};

纯元件

库支持纯组件:

  • 只在安全部门改革期间做过一次
  • 客户端跳过水合
  • 可通过 pureComponents 选项
    • useMdx
    • useMdxSsr
    • getSsrRenderer
    • getAsyncSsrRenderer

示例

export const PURE_COMPONENTS = {
  KatexFormula, // Will render once on server and not hydrate
  Label, // on client
  CompatTable,
  Alert,
};

同步组件加载

这个 useMdx 财务报告和审定财务报表 useMdxSsr 钩子支持可选 idMdxComponentLoader 能够同步加载 MDX 组件的参数:

interface PageProps {
  html: string;
  mdxArtifacts?: MdxArtifacts;
  withLoader?: boolean;
}

const Page: FC<PageProps> = ({html, mdxArtifacts}) => {
  const [isSuccess, setSuccess] = React.useState(false);
  const [data, setData] = React.useState<IdMdxComponentLoader['data']>(undefined);

  useMdxSsr({
    // ...other options
    idMdxComponentLoader: {isSuccess, data},
  });

  useEffect(() => {
    (async () => {
      const idMdxComponent: Record<string, React.ComponentType<MDXProps>> = {};

      for (const [artifactId, code] of Object.entries(mdxArtifacts?.idMdx ?? {})) {
        const fn = await asyncExecuteCode(code);
        idMdxComponent[artifactId] = fn(runtime).default;
      }

      setData(idMdxComponent);
      setSuccess(true);
    })();
  }, [mdxArtifacts]);

  // ...rest of the component
};

汇编选项

所有渲染器的功能( A)getSsrRenderer, (中文(简体) ), getAsyncSsrRenderer, (中文(简体) ), getRenderer)接受可选的MDX编译选项:

const renderer = await getAsyncSsrRenderer({
  components: SSR_COMPONENTS,
  pureComponents: PURE_COMPONENTS,
  compileOptions: {
    // MDX compilation options here
  },
});

这允许在保持库核心功能的同时,对MDX编译过程进行精细控制.

许可证

麻省理工学院

版本与发布记录

@diplodoc/mdx-extension 共发布 37 个版本,首次发布于 2025/05/26;过去 12 个月发布了 7 个版本。

版本发布日期距今
1.10.1latest2026/06/174 个月前
1.10.02026/06/174 个月前
1.9.02026/05/046 个月前
1.8.12026/04/306 个月前
1.8.02026/04/166 个月前
1.7.22026/04/146 个月前

关于 @diplodoc/mdx-extension 的常见问题

如何安装 @diplodoc/mdx-extension?

在项目目录运行 npm install @diplodoc/mdx-extension,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0)、react-dom(^16.14.0 || ^17.0.0 || ^18.0.0 || ^19.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@diplodoc/mdx-extension 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@diplodoc/mdx-extension 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@diplodoc/mdx-extension 可以商用吗?

@diplodoc/mdx-extension 使用 未声明 许可。package.json 没有声明许可证。没有许可证的代码默认保留全部权利,商用前请联系作者或查看仓库中的 LICENSE 文件。以上为概括,不构成法律意见,请以许可原文为准。

@diplodoc/mdx-extension 的下载量有多少?

根据 npm 官方下载统计,@diplodoc/mdx-extension 在 2026/10/13 – 2026/11/11 这 30 天内被下载 6,632 次,日均约 221 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@diplodoc/mdx-extension 还在维护吗?

最新版本 1.10.1 发布于 2026/06/17(4 个月前);至今共发布 37 个版本,其中过去 12 个月发布了 7 个;首次发布于 2025/05/26。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。