在 TypeScript 中处理 Markdown:从解析到自定义插件
Markdown 仍然是文档、博客和教育平台中最流行的标记语言之一。在使用 TypeScript 开发时,不仅需要显示 Markdown,还需要灵活地管理其转换过程。在本文中,我们将介绍三个关键库,它们将帮助您将 Markdown 集成到您的 TypeScript 项目中,并展示如何创建自己的扩展。
为什么 TypeScript 对处理 Markdown 很重要?
TypeScript 添加了严格的类型检查,这在处理用户生成内容时至关重要。您可以确切地知道从 Markdown 文件中获取的数据类型,并避免运行时错误。此外,TypeScript 简化了解析器的插件和中间件的创建。
流行库概述
- marked — 最快、最简单的解析器。配置最少,性能出色。
- unified / remark — 用于语法分析的生态系统。允许创建复杂的转换链(AST -> HTML -> React)。
- showdown — 一个轻量级替代方案,支持扩展,文档完善。
示例 1:使用 marked 进行基础解析
marked 库非常适合快速入门。通过 npm 安装:
npm install markedTypeScript 的类型定义已包含在内。使用示例:
import { marked } from 'marked';
const markdownContent = `# 你好,TypeScript!这是**粗体文本**和`代码`。- 列表项- 另一个`;
const html = marked.parse(markdownContent);console.log(html);// 输出:<h1>你好,TypeScript!</h1>// <p>这是 <strong>粗体文本</strong> 和 <code>代码</code>。</p>// <ul><li>列表项</li><li>另一个</li></ul>对于异步操作,请使用 marked.parseAsync()。这在从网络加载文件时非常有用。
示例 2:带类型检查的自定义渲染器
有时需要更改默认行为。例如,为链接添加类或处理图像。让我们在 TypeScript 中创建一个自定义渲染器:
import { marked, Renderer } from 'marked';
interface CustomRenderer extends Renderer { link(href: string, title: string | null, text: string): string;}
const renderer: Partial<CustomRenderer> = { link({ href, title, text }) { return `<a href="${href}" target="_blank" rel="noopener noreferrer" class="external-link">${text}</a>`; }};
marked.use({ renderer });
const markdown = '访问 [PythonLib](https://pythonlib.ru)';const result = marked.parse(markdown);// <a href="https://pythonlib.ru" target="_blank" class="external-link">PythonLib</a>Partial<CustomRenderer> 类型确保我们只覆盖所需的方法。
示例 3:通过 unified 和 remark 处理 AST
如果您需要完全控制文档结构,请使用 unified 和 remark。安装:
npm install unified remark-parse remark-stringify remark-html解析为语法树 (AST) 并返回的示例:
import { unified } from 'unified';import remarkParse from 'remark-parse';import remarkStringify from 'remark-stringify';import remarkHtml from 'remark-html';
const markdown = '# 标题这是**重要的**。';
const file = await unified() .use(remarkParse) // 解析为 AST .use(remarkStringify) // 返回 Markdown(用于检查) .process(markdown);
console.log(String(file)); // 原始 Markdown
const htmlFile = await unified() .use(remarkParse) .use(remarkHtml) // 转换