跳到主要内容

自定义asciinema代码成功失败分析

很好,我们可以总结一下为什么之前失败,而现在成功了:


1️⃣ 之前失败的原因

  1. 使用 type: 'jsx', value: '<AsciinemaPlayer … />'

    • MDX loader 不会执行字符串形式的 JSX

    • 它只会把它当作文本节点渲染到页面上。

    • 结果页面显示 <AsciinemaPlayer … /> 字符串,而不是 React 组件。

  2. 尝试在 AST 中放 React 元素对象 (React.createElement)

    • Remark 插件本质上只生成 AST 节点。

    • MDX loader 不认识 data.reactElement,无法把 React 对象渲染成元素。

    • 所以即便在 AST 中放了 React.createElement(BrowserOnly, …),页面也不会显示。

  3. BrowserOnly 也无效

    • BrowserOnly 只是一个 React 组件,它需要在 React 渲染阶段被调用。

    • 之前的插件生成的内容根本没有变成 React 组件节点,MDX loader 只是当成文本。


2️⃣ 为什么现在成功了

  1. 生成了 mdxJsxFlowElement 节点

    • MDX v2 loader 识别 mdxJsxFlowElement AST 节点,并直接转换为 React 元素。

    • 这样生成的 AST 相当于在 Markdown 中写了 JSX:

      mdx
      <AsciinemaPlayer file="…" autoplay={true}>
      <span>5, 开始</span>
      </AsciinemaPlayer>
    • MDX loader 会在编译阶段把它变成可渲染的 React 组件。

  2. 属性和 children 都是标准 AST 节点

    • attributes 使用 mdxJsxAttribute,MDX loader 会解析 true/false/number/string

    • children 使用 mdxJsxTextElement + text 节点,MDX loader 会转换为 React 子元素。

  3. 完全遵循 MDX AST 规范

    • 不生成额外的 data.reactElementtype: 'jsx', value: ''

    • 因此 MDX loader 可以完整渲染,最终页面显示播放器,而不是字符串。


3️⃣ 核心总结

方案原因结果
type: 'jsx', value: '<… />'只是文本,不会被编译执行页面显示字符串 <… />
data.reactElement = React.createElement(...)MDX loader 不识别 React 对象页面显示空或无效果
mdxJsxFlowElement + mdxJsxAttribute/children完全符合 MDX AST 规范页面成功渲染为 React 组件

结论
在 Remark 插件中生成 JSX,必须生成标准 MDX AST 节点 (mdxJsxFlowElement),才能被 MDX loader 渲染成 React 组件。


Markdown → Remark → MDX → React 渲染 流程

  1. Markdown 解析为 Remark AST

    • Markdown 文件被解析成树形结构(AST)。

    • 每个 code block、段落、标题等都是 AST 节点。

  2. Remark 插件处理 AST

    • 插件遍历 AST,找到目标节点(比如 code 节点)。

    • 插件可以修改节点类型或内容。

    • 关键:要生成 JSX,必须生成 MDX AST 节点mdxJsxFlowElement),而不是 React 对象或普通文本。

  3. Remark AST → MDX AST

    • MDX loader 会把 AST 转换成 MDX AST,其中 mdxJsxFlowElement 节点会被标记为 JSX 组件节点。

    • 属性用 mdxJsxAttribute,子节点用 mdxJsxTextElement

  4. MDX AST → Babel/React 编译

    • MDX loader 将 MDX AST 转为 React 组件代码。

    • JSX 节点会变成 React.createElement(Component, props, children)

  5. React 渲染

    • 最终 React 渲染生成真实 DOM。

    • 你的 <AsciinemaPlayer> 会被调用,BrowserOnlyasciinema-player 执行,生成播放器 DOM。


关键点总结

  • 失败原因:生成的只是文本或 React 对象,MDX loader 不执行。

  • 成功原因:生成了标准 MDX AST 节点,MDX loader 会正常编译成 React 元素。

  • 经验:Remark 插件想在 MDX 中生成组件,必须遵循 MDX AST 规范,直接生成 mdxJsxFlowElement 才行。


这也是为什么你现在在 Markdown 中写 code block 就可以直接显示播放器,而不再显示字符串。