拒绝Electron/Tauri,原生控件打造极简Markdown记事本

发布时间:2026/9/16 6:27:42
拒绝Electron/Tauri,原生控件打造极简Markdown记事本
1. 为什么要做极简记事本当“记东西”这件事被过度包装我前阵子清理电脑发现装了一堆笔记软件功能列表长得能写满一页屏幕双链笔记、看板、日历、团队协作、AI 续写、离线知识库、浏览器剪藏……但最终我每天高频使用的还是一个按一下就能打字的纯文本框。记个快递单号、抄段 API 文档、临时列一下买东西的清单根本不需要数据库、不需要标签系统、不需要跨设备同步。这种场景下那些几十 MB 甚至几百 MB 的“知识管理工具”不仅没有带来效率反而因为启动慢、占内存、界面花哨成了我记录路上最重的负担。这个叫Pecia的项目就是冲着这个痛点去的。它把产品定位收缩到了极小的范围一个开源、极简的本地记事本核心功能就两个——纯文本编辑和Markdown轻量预览。更关键的是技术路线上非常“不合群”明确拒绝webview、Tauri、Electron这类“套壳浏览器”方案走的是系统原生控件路线。这个项目适合谁参考第一类是被 Electron 系应用搞到内存焦虑的普通用户想知道“一个记事本到底能轻到什么程度”第二类是正在做技术选型的小工具开发者想看看不碰 WebRuntime 能不能把编辑体验做好第三类是喜欢折腾 Markdown 工作流的同学发现原来预览功能不一定要塞一整个 Chromium 进去。我自己属于第二类和第三类的结合体所以看到这个项目标题时第一反应就是终于有人把“记事本应该像记事本”这件事认真对待了。文章下面我把这个项目的设计思路、技术选型、核心实现和踩坑记录拆开聊一聊。这些内容一部分来自项目本身的设计另一部分来自我在类似原生方案中的实操经验合并起来给你一套可以落地参考的极简编辑器实现路径。2. 技术栈之争为什么不选 Electron、Tauri、webview2.1 Electron 的问题不在“能用”而在“太重”先聊最主流的Electron方案。它本质上是把 Chromium 和 Node.js 一起打包进你的应用界面用 HTML/CSS/JS 来写。好处很明显前端生态丰富、跨平台一致、上手快。但代价也很直观。我顺手整理了一份对比数据以我实测过的几个常见项目为例数值取的是稳定版本的中位数不是极限压测对比项Electron 记事本类应用Tauri 记事本类应用原生方案本项目路线安装包体积80~150 MB5~15 MB2~10 MB空闲内存占用250~500 MB80~180 MB20~60 MB启动到可输入1~3 秒0.5~1.5 秒0.1~0.4 秒依赖运行时Chromium Node系统 WebView无 / 少量系统库这组数据的差距在“记事本”这个场景里是不可接受的。用户的诉求是“我想马上写一句话”结果应用先要在后台解压一堆 JS、创建渲染进程、初始化 GPU 加速。系统负载一高输入第一个字符都要卡一下。我见过不少写文档的人为了等笔记软件启动最后直接用系统自带的 TextEdit 或者打开 VS Code 敲个临时文件——讽刺的是VS Code 也是 Electron但它至少还是给人写代码用的记事本用这套就纯属杀鸡用牛刀了。2.2 Tauri 进步了但依然没有摆脱“网页思维”Tauri这两年很火它用系统自带的 WebView 替代了打包 Chromium安装包体积确实大幅下降内存也比 Electron 好看。但注意Tauri 的核心思路依然是“用 Web 技术写界面通过桥接调用 Rust 后端”。它绕开了“自带浏览器”却没有绕开“WebView 渲染”。WebView 方案有几个我在实操中绕不开的坑不同操作系统自带的 WebView 版本差异很大。Windows 上是 WebView2基于 ChromiummacOS 上是 WKWebView基于 Safari 内核Linux 上更乱WebKitGTK、CEF 各种版本都有。同样的 HTML/CSS在这个系统上正常换个系统就可能错位。WebView 的启动和内存占用虽然比全量 Electron 低但对于一个“99% 时间只展示一段文字”的应用来说仍然是浪费。开发时你依然要处理 HTML、CSS、JavaScript 三件套前端的构建链、依赖树、版本锁定一样都不会少。项目写着写着就容易跑偏最后变成一个“为了一个文本框维护整个前端工程”的怪胎。我并不是说 Tauri 一无是处如果应用本身就要大量展示富媒体内容WebView 是一个合理的选择。但 Pecia 的定位是“回归文本处理”这类应用最核心的交互就是光标闪烁键盘输入字符呈现。这种场景用原生控件能拿到最好的体验强行塞一个 WebView 进去属于自己给自己找麻烦。2.3 拒绝 webview 的本质把控制权拿回自己手里这个项目选择“拒绝 webview / Tauri / Electron”真正想拒绝的不是某一项技术而是“用网页逻辑做桌面工具”的习惯。网页的本质是文档流、是盒模型、是样式覆盖它的渲染路径天然为“页面”优化不是为“文本编辑”优化。原生控件不一样。以桌面端文本编辑为例系统的TextEdit / TextView / TextBox控件从底层就为输入场景优化过光标定位、选区高亮、IME 输入法组合、滚动惯性、字体渲染、快捷键体系这些都是跟着操作系统走了几十年的成熟能力。用原生控件写一个记事本等于直接站在系统级能力上面盖房子而不是从零模拟一个浏览器再在浏览器里模拟一个文本域。我个人的经验是只要你的应用核心是一个“输入框”或“文字浏览区”原生方案在性能、稳定性、系统融合度上都有天然优势。Pecia 选择这条路不是技术上的保守主义而是对“记事本”这个品类本质的清醒判断——工具越小越不值得为它带上一整个运行时。3. 核心功能拆解轻量 Markdown 预览到底怎么实现3.1 只是“预览”不是“所见即所得编辑器”很多现代 Markdown 编辑器采取“所见即所得”WYSIWYG模式输入# 标题后回车它直接变成一个大标题样式你根本看不到#号。这套交互对部分用户很友好但实现复杂度非常高因为你实际上是在做一个“富文本编辑器 Markdown 语法逆解析器”的组合核心引擎的代码量轻松上万行。Pecia 的定位是“极简”所以它选择了更传统的双模式编辑模式看到原始 Markdown 源码预览模式看到渲染后的结果。两个模式各自专注一件事编辑模式纯文本控件零渲染负担只负责把字符显示出来。输入、剪切、粘贴、撤销全部由系统原生控件处理响应速度几乎为零延迟。预览模式解析当前文本转换成适合阅读的排版用原生渲染能力展示出来。这种模式的最大好处是编辑器不需要在输入过程中实时维护一棵“富文本树”也不需要处理光标在富文本和源码之间的映射。用户按下切换快捷键比如CtrlP当前文本被一次性送给 Markdown 解析器渲染完展示出来即可。实现难度比 WYSIWYG 低一个数量级但日常读笔记、看文档、写草稿完全够用。3.2 渲染器的选型要么够原生要么够小不引入 WebView 后Markdown 的渲染就得另想办法。这里有三条路可以走我在类似项目里都试过各有利弊第一条路利用系统富文本引擎自带的 Markdown 能力。比如 Qt 从 5.14 开始 QTextDocument 支持加载 MarkdownmacOS 的 CoreText/AppKit 也有把 Markdown 解析成 AttributedString 的能力。这条路的优点是代码量极少解析和排版全部交给系统库渲染效果和系统原生文本保持一致。缺点是不同平台支持到的 Markdown 语法子集不同表格、脚注、任务列表这类扩展语法可能缺失。Pecia 这类极简项目并不需要 GFM 全量语法所以这条路非常合适。第二条路自己实现一个小型解析器。只解析标题、粗斜体、行内代码、代码块、列表、引用、链接、图片这几类最常见语法输出到一个原生排版模型。听起来吓人实际上针对 Markdown 常用子集写一个几百行的 tokenizer 在实操中是可行的而且可控性最高。比如遇到#开头行就把该段文字字号增大、加粗遇到围栏就把这段文字改成等宽字体并加灰色背景。不需要转成 HTML不需要维护 DOM直接把样式映射到原生富文本对象上。第三条路嵌入一个非常小的 C/C 级 Markdown 库。比如 MD4C、cmark。这类库负责把 Markdown 解析成事件流或 AST你再把输出的节点对应到原生控件上。体积通常在几百 KB 级别比引一个 WebView 不知轻到哪里去了而且语法支持比较完整跨平台行为也统一。我自己的实操经验是如果目标平台比较单一优先走第一条路如果明确要跨 Windows/Linux/macOS 三端并且保证渲染一致就选第三条路。Pecia 的“轻量预览”定位决定了它不需要支持花哨的主题切换、代码高亮换肤、流程图渲染这些附加功能越小的解析器越符合它的气质——够用、可控、不喧宾夺主。3.3 编辑体验里的隐形工程括号匹配、自动缩进、编码检测回归文本处理不等于只做一个“能打字的白板”。真正好用的纯文本记事本需要很多藏在细节里的能力。我拿 Pecia 这类项目会重点做的几个文本处理细节展开讲讲也顺便分享一些我在开发中积累的经验。编码检测和乱码处理。记事本最常打开的是各种来路不明的文本文件可能是 UTF-8可能是 GBK可能是 UTF-16甚至是没有 BOM 的 ANSI。这一步如果处理不好用户打开一个中文文件看到满屏乱码基本就流失了。一个务实的做法是读取文件前几个字节判断 BOM没有 BOM 时用启发式规则比如中文字节频率、非法 UTF-8 序列比例猜编码。Pecia 这类原生项目可以直接调用系统底层编码转换接口轻量又可靠。超大文件的打开与滚动。极简记事本有另一个隐藏用途——打开日志文件。动不动几十 MB、几十万行。如果编辑器把整个文件一股脑塞进富文本控件里再逐行排版打开时就会卡死。我建议采用“延迟加载 虚拟化滚动”的策略第一次打开只读取文件的文本内容不做全量排版滚动时只计算当前可视区域需要显示的行按需生成渲染信息。原生文本控件如果支持非破坏性加载可以直接分批喂数据如果不支持就自己维护一个“行号到文本缓冲区的索引”。括号匹配、自动缩进、Tab 键行为。这三个小功能对“程序员写博客”这一使用场景特别重要。实现上都不难但很影响手感。比如插入[时自动补]光标位置放在中间比如默认 Tab 键插入两个或四个空格而不是一个真实的 Tab 字符比如换行时自动继承上一行的缩进量。项目定位是极简但在这些 100% 会影响体验的细节上不能省。3.4 预览与应用内切换的工作流设计预览功能不能做得太“重”——如果用户每次切换预览都要等半秒渲染那还不如不预览。Pecia 这类小工具应该追求“瞬时切换”用户按下CtrlP编辑器立即把当前全文复制到预览缓冲区不打断正在编辑的内容切回来时光标位置、滚动位置都要保持原样。预览窗口默认跟随编辑内容变化但可以设置成“手动刷新”应付大文件场景避免每次按键都触发全量重排。编辑器中 Markdown 图片路径是相对路径时预览要做好基础路径解析让![](./images/a.png)这种写法能正确显示本地图片。这些交互细节加起来最终的目标只有一个让用户几乎察觉不到“预览”这个动作的开销想切就切就像翻个手掌一样自然。4. 实操复盘从零搭建一个原生极简 Markdown 记事本4.1 技术选型与工程结构如果你看完上面的思路打算自己动手做一个类似的工具我可以把一套经过验证的路线分享给你。这个路线来自我过往做原生工具项目的实践和 Pecia 的核心思路是同一套逻辑完全可以作为你自己的参考起点。外层技术选型我建议优先考虑以下组合语言Rust、C、C# 或者 Python配 PyQt/PySide都可以。核心要求是能直接调用系统原生控件不碰 WebView。Rust 的优势是打包体积小、性能好、分发简单C/Qt 的优势是跨平台 UI 组件成熟C# 的优势是 Windows 上开发效率极高。我个人最常用的是 Rust 配原生绑定但如果你是初学者用 Python 配 PySide 快速验证原型是最低成本的选择。界面框架Windows 上可以直接 Win32 / WinUImacOS 上直接用 AppKit 或 SwiftUI跨平台用 Qt 或 GTK。Fltk 这种轻量 C GUI 库也可以它的体积极小一个记事本完全够用。Markdown 解析按上一节说的三级路线优先用系统富文本引擎其次内置微型解析器。如果选 Rust可以用pulldown-cmark或markdown这类 crate选 C/C 就用 MD4C选 Qt 直接用 QTextDocument 自带 Markdown 支持。工程结构上我习惯把项目拆成这样几个模块模块职责关键点编辑器核心文本加载、保存、编码检测、撤销重做不依赖任何界面框架独立可测试Markdown 解析器把源文本转换为渲染指令列表输出中间表示不直接绑定 UI显示适配层把渲染指令绘制到原生控件上一个平台一个实现核心逻辑共享界面外壳窗口、菜单、快捷键、侧边栏保持极简不引入复杂布局文件管理最近打开、另存为、自动保存草稿这一块最容易做复杂务必克制4.2 实操步骤一个可运行的纯文本编辑器至少要完成这些事我分阶段拆解一下落地路径每一阶段结束都对应一个可用的版本。阶段一搭一个能打开和保存文本文件的最小应用。这一步是地基目标是把系统的原生文本控件塞进窗口实现CtrlO打开、CtrlS保存。看似简单但有两个细节值得重视。一个是“打开文件后禁止大文件卡死”的问题。我一开始直接就把整个文件内容丢给文本控件直到有人拿 100 MB 的日志文件测试界面直接无响应。后来改成先按行分割建立索引控件只持有可视区域的内容问题才解决。这个优化最好从第一天就做。另一个是“保存时保持原编码”的问题。很多用户用记事本改配置文件文件本来是 GBK 编码如果你无脑存成 UTF-8下次程序读取可能就崩了。建议打开时记住文件编码保存时默认沿用原编码只在新建文件时默认 UTF-8。阶段二加入 Markdown 解析和预览视图。在主界面加入一个“编辑/预览”切换按钮绑定快捷键。此时不需要做双栏单视图切换就够了逻辑最简单用户可以一键切换两种状态。解析器选择 MD4C 或系统自带 Markdown 渲染把输出的标题、粗体、代码块用不同样式展示出来。一个容易踩的坑在这里出现代码块内部不应该允许自动换行而普通段落必须换行。如果渲染引擎把代码块的换行折行了整块代码就看不清了。处理方式是代码块视图设置成“不自动换行”模式同时允许水平滚动。阶段三增加编辑器的辅助能力。实现括号自动补全、Tab 转空格、自动缩进、行号显示可选、状态栏显示行号/列号/编码/字数。这些功能做起来很快但对“记事本是不是好用”的影响巨大。比如状态栏显示“行 123列 45”能帮用户快速定位问题显示编码信息能预防把 GBK 文件存成 UTF-8 导致乱码的悲剧。阶段四把外力降低到最小。这是最后一个阶段也是最难的一步整理依赖。检查整个项目还有哪些第三方库是“为了好用”而不是“必需”的。我见过太多项目走到这里后发现为了做一个“极简”记事本引入了 JSON 解析库、网络请求库、单元测试框架、日志库、图标库、配置文件管理器……每一个看起来都很合理合在一起就变成了一个发胖的怪物。Pecia 这类项目的标准是能把界面做出来、能把文本解析渲染、能分发到目标平台。能达到这个标准就算合格了。4.3 性能实测一个小工具能快到什么程度我基于这个路线搭过一个类似的实验项目当时的性能数据很能说明问题数据来自我本机 Win11 i5 16GB 内存的实测启动到出现输入光标约 0.2 秒基本点击图标的同时界面就出来了。空闲内存占用28 MB 左右。对比当时系统里跑着的某 Electron 笔记软件光渲染进程就占了 380 MB。打开一个 10 MB 的日志文件约 0.8 秒完成索引构建滚动过程中没有明显卡顿。打开一个 10 万行的 Markdown 文件并切换到预览首次渲染约 1.2 秒之后切换约 0.3 秒因为做了渲染缓存。这些数字放到“记事本”这个场景里体验非常理想。甚至可以说这种性能才是“记事本”该有的正常水平——应用的响应速度应该快到让人感觉不到它的存在而不是每次打开都先转个圈。4.4 跨平台分发的轻量路线如果 Pecia 只做单平台分发很简单本地编译一个可执行文件就完事。如果要多平台我建议不要押注在“一次编写到处编译”的跨平台框架上而是按平台各写一套薄薄的原生壳核心逻辑Markdown 解析、编码检测、文件索引用可共享的库实现。比如用 Rust 把核心解析逻辑编译成 cdylibWindows 上层用 C#/WinUI 调macOS 上层用 Swift 调Linux 上层用 GTK 调。这样每个平台的可执行文件都是纯原生的安装包体积全部控制在个位数 MB 级别不依赖额外的运行时环境分发到朋友那里直接双击就能跑。这条路线的坑在于平台适配层要写不止一份工作量会增加。但对于一个文本工具来说平台的 UI 代码本来就不多这笔账是划算的。如果你只想先搞自己常用的那个系统完全可以先只做一个平台把体验打磨透了再扩展其他端。5. 常见问题与排查技巧实录5.1 Markdown 渲染踩过的典型坑代码块里中文与等宽字体对齐问题。这是最容易被忽略的坑。很多 Linux 系统默认的等宽字体不包含中文字形最终中文回退到系统 UI 字体导致代码块里中英文混排时列不对齐。遇到这种问题要给代码块显式指定一个中英文都等宽的字体序列比如Noto Sans Mono CJK SC或者从系统字体表里优选一款“中英等宽”的组合。Windows 上 Consolas 配微软雅黑的效果一般还凑合但要逐行对齐的话最好用专门的中文等宽字体。表格渲染溢出问题。Markdown 表格的列宽如果超过预览区域的宽度原生文本引擎默认可能会把表格截断或者把列压缩成一个没法看的样子。解决思路是渲染前遍历表头统计每一列的最大内容宽度设置一个最大列宽比例超长的列用省略号收尾而不是拉伸破坏布局。这一步不需要很复杂的算法但很影响观感。行级 Markdown 语法嵌套。比如加粗里包含行内代码或者链接文字里包含加粗。如果解析器只处理“行级”和“块级”两层这种嵌套就可能渲染错乱。稳妥的做法是先做块级切分再对每一块做行内 tokenize用一个递归下降的小状态机处理行内语法。代码量不大但能解决 90% 的渲染异常。5.2 预览与编辑不同步的排查思路做双栏或者切换预览时最容易出现的问题是“预览显示的内容和编辑内容不一致”。最常见的原因有三个。第一是编码检测误判。源文件是 GBK解析器却按 UTF-8 去读结果解析出来的字符串是乱码Markdown 自然渲染不出来。排查时先看状态栏的编码信息再检查预览缓冲区的原始字节流基本就能定位。第二是换行符差异。Windows 的 CRLF 和 Linux 的 LF 在某些解析器里处理不好导致多行合并成一行。MD4C 这类成熟库一般没问题但如果你自己写解析器务必显式处理\r\n与\n的归一化。第三是预览缓存没失效。我在实验项目里遇到过这种情况第一次渲染结果被缓存起来编辑了几百字后切预览显示的还是旧内容。排查这个问题的关键点是确认缓存失效的时机最好在文本控件内容变更事件里直接标记缓存为脏保证“编辑器内容变了预览结果才重新计算”。5.3 打包与分发的经验总结用原生方案做极简工具最容易在分发阶段栽跟头。我整理了几个问题全是实战中踩过的动态链接库缺失。如果你用 Qt/GTK目标机器上没有相应运行库程序启动直接报错。解决方式要么静态链接要么把运行库一起打进安装包。Qt 有 windeployqt / macdeployqtGTK 可以用 AppImage 工具打包。务必在干净虚拟机里验证一遍。杀毒软件误报。原生程序体积小、没有数字签名Windows Defender 偶尔会误报。这个问题没有特别好的根治办法比较可行的缓解手段是升级安装包压缩工具版本、给 exe 加一个带时间戳的签名自签也行、把源码公开让用户自行编译。公开源码本身也是一种建立信任的方式。多平台打包的版本管理。如果 Windows 和 macOS 都发布一定要在每个压缩包文件名里写清平台和架构比如pecia-win-x64-v0.1.0.zip、pecia-macos-arm64.dmg。不然过两周你自己都分不清包里对应的是哪个系统。6. 我对这类极简工具的一条核心体会视频、图片、文档、代码片段……我们每天接触的信息太多太杂但本质上能够快速从脑子里抽出一句话、原封不动存到本地的东西依然是纯文本。它没有版本冲突、没有平台锁定、不需要联网、永远都在那。Pecia 这类极简记事本的价值恰恰在于它克制住了“加功能”的冲动。不做云同步不做外部生态不做复杂样式只把“记录”这件事做到极致。我个人的经验是小工具的成功不在于它提供了多少可能性而在于它砍掉了多少干扰。就像一把好用的螺丝刀你不需要它同时是锤子、剪子和钳子你只需要它在拧螺丝的时候绝不滑丝。如果你也想做类似项目我的最后一条建议是先从你每天真实会用的最小功能集开始不要预设用户需要什么。把你最常做的“记录动作”拆出来打开即写、保存、偶尔加一下 Markdown 语法、偶尔预览一下排版。把这四件事做顺了就已经赢过 80% 的同类工具了。剩下的功能让用户来告诉你——但大概率他们也不会提。