md-preview 源码解析 — Rust 写的超轻量 Markdown 预览器

> 一句话版本:一个用 Rust 写的 Markdown 预览工具,整个核心逻辑只有 ~400 行代码,编译出 ~1MB 二进制,用系统原生 WebView 渲染,不捆绑 Chromium。是一个"Rust + wry 构建桌面应用"的教科书级示例。

项目信息
来源https://github.com/vorojar/md-preview
作者vorojar
创建时间2026-04-11
语言Rust
Stars19Forks 2
许可证MIT
核心代码单文件 `src/main.rs`,~400 行

项目结构


md-preview/
├── src/main.rs              ← 核心逻辑(唯一 Rust 源文件)
├── Cargo.toml               ← 6 个依赖
├── assets/
│   ├── hljs/highlight.min.js      ← 语法高亮(编译进二进制)
│   ├── hljs/github.min.css        ← 亮色主题
│   └── hljs/github-dark.min.css   ← 暗色主题
├── docs/index.html           ← 落地页(SEO 优化,中英双语)
├── bundle.sh                ← macOS .app 打包脚本
├── install.sh               ← 安装 + 注册为 .md 默认程序
└── screenshots/welcome.png

技术栈与依赖


[dependencies]
wry = "0.50"           # WebView(核心:用系统浏览器引擎渲染 HTML)
tao = "0.33"           # 窗口管理(跨平台窗口、事件循环)
pulldown-cmark = "0.12" # Markdown 解析(CommonMark + GFM)
rfd = "0.15"            # 原生文件对话框
notify = "7"            # 文件监听(热重载)
open = "5"              # 打开 URL/文件(macOS 用)

6 个依赖,极简。对比 Electron 需要 Node.js + Chromium,这里零运行时依赖。

核心架构(main.rs 源码解析)

1. Markdown → HTML 转换


fn md_to_html(md: &str) -> String {
    let opts = Options::ENABLE_TABLES
        | Options::ENABLE_STRIKETHROUGH
        | Options::ENABLE_TASKLISTS
        | Options::ENABLE_HEADING_ATTRIBUTES;
    let parser = Parser::new_ext(md, opts);
    let mut html_out = String::new();
    html::push_html(&mut html_out, parser);
    html_out
}

使用 pulldown-cmark,支持 GFM 扩展(表格、任务列表、删除线、标题锚点)。纯 Rust 实现,无外部依赖。

2. HTML 页面生成(CSS 全内联)


fn build_page(body: &str) -> String {
    format!(r#"<!DOCTYPE html><html><head>...
        <style>/* 完整 CSS 样式 */</style>
        <script>{hljs_js}</script>
        <style id="hljs-light">{css_light}</style>
        <style id="hljs-dark" media="not all">{css_dark}</style>
    </head><body>{body}</body>
    <script>hljs.highlightAll();</script></html>"#,
        css_light = HLJS_LIGHT,
        css_dark = HLJS_DARK,
        hljs_js = HLJS_JS,
        body = body
    )
}

关键设计: