You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Unified解析内嵌HTML的Markdown的流程优化咨询

优化方案

你当前的流程冗余核心在于完全不需要「Markdown→HTML→Markdown」的来回转换步骤,绕这一圈的唯一作用是把内嵌HTML标签转为标准Markdown元素,我们可以直接在首次解析得到的AST层处理这个需求,省去2次全量解析+1次序列化+1次反序列化的开销。

核心思路

  1. 直接用remark-parse+remark-gfm解析原始GFM文本得到初始AST,此时内嵌的HTML标签会被识别为type: 'html'的节点
  2. 写一个轻量的AST遍历逻辑,把html节点里的对应标签(比如<img>)转换为标准Markdown AST节点(比如type: 'image'的节点)
  3. 处理完成的AST直接传入你的parseBlocks方法即可

优化后代码

import unified from 'unified';
import markdown from 'remark-parse';
import gfm from 'remark-gfm';
import { visit } from 'unist-util-visit';
import { parseBlocks } from './parser/internal';
import type { Root, Html, Image } from './markdown';
import type { ParsingOptions } from './types';

// 简单的HTML标签属性解析工具,不需要引入重型HTML解析器
function parseImgTag(html: string): Omit<Image, 'type'> | null {
  const imgMatch = html.match(/<img\s+[^>]*src\s*=\s*["']([^"']+)["'](?:\s+alt\s*=\s*["']([^"']*)["'])?[^>]*>/i);
  if (!imgMatch) return null;
  return {
    url: imgMatch[1],
    alt: imgMatch[2] || '',
    title: null // 需要title属性的话可以自行补充匹配逻辑
  };
}

export async function markdownToBlocks(body: string) {
  // 直接解析原始GFM得到初始AST
  const root = unified().use(markdown).use(gfm).parse(body) as unknown as Root;

  // 遍历AST处理内嵌HTML节点
  visit(root, 'html', (node: Html, index, parent) => {
    // 处理img标签
    const imgAttrs = parseImgTag(node.value);
    if (imgAttrs && parent && typeof index === 'number') {
      // 把html节点替换为标准image节点
      parent.children.splice(index, 1, {
        type: 'image',
        ...imgAttrs
      } as Image);
    }
    // 其他需要处理的HTML标签可以在这里补充对应逻辑
  });

  // 直接传入处理后的AST即可
  return parseBlocks(root);
}

补充说明

  • 如果需要处理更多HTML标签(比如<a>、<blockquote>等),只需要在遍历逻辑里补充对应的解析和转换规则即可
  • 如果HTML标签逻辑非常复杂,可以引入轻量的HTML解析工具来解析html节点的内容,不需要走全量的rehype转换流程
  • 相比原实现,优化后仅需要1次Markdown解析,性能提升至少3倍以上

内容的提问来源于stack exchange,提问作者Richard Robinson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.15 07:15:03