Excalidraw 是一个跑在浏览器里的白板:左边选形状,中间拖出方框,连线,写字,最后导出成 PNG 或 SVG。手绘风格的线条是它的招牌,画一张 5 个元素的流程图不到 1 分钟。
这套东西平时用官方站点就行。这篇文章做的是另一件事:把它从源码构建成 22.99 MB 的静态包,塞进便携版 node 当服务器,双击就能离线用。
整个过程实测了 4 个环节的耗时:装依赖 646 秒 / 构建 packages 76 秒 / 构建应用 43.58 秒 / 首屏 4.35 秒。
一块不用登录的白板
打开就是一个画布,工具在顶部横排,属性面板跟着选中对象出现在左侧。界面语言会自动切成中文,没让我选。
| 项目 | 数值 | 说明 |
|---|---|---|
| 源码包 | 36990426 | 字节,zip |
| 依赖目录 | 805 | MB |
| 构建产物 | 506 | 个文件 |
| 产物体积 | 47526436 | 字节 |
| 去掉 sourcemap | 22997644 | 字节,383 个文件 |
| 主包 | 1898235 | 字节,index 那个 |
| 顶部工具 | 12 | 个,每个带单键快捷键 |
顶部工具栏一共 12 个工具,每个都带单键快捷键:选择 V / 矩形 R / 菱形 D / 椭圆 O / 箭头 A / 线条 L / 自由书写 P / 文字 T / 便签 N / 橡皮 E,另有抓手 H 与锁定 Q。最右边的三点是「更多工具」,额外的图形藏在那里。

装之前先看三件事
依赖装得慢,646 秒
这是个 monorepo,yarn install 跑了 646 秒才结束。慢的原因不是包多,是 workspace 之间要建立链接,磁盘上要写几万个小文件。
装完 node_modules 是 805 MB、几万个文件。想省时间,直接把别人的 node_modules 拷过来也行,版本对得上就不用重装。
构建分两步,先 libraries 后应用
直接 vite build 会失败,因为 packages/ 下的几个库还没产出 esm 版本。必须先跑 build:packages,再构建应用。
yarn build:packages # 76 秒
cd excalidraw-app
node ../node_modules/vite/bin/vite.js build # 43.58 秒
第二步退出码是 2,看着像失败。实际产物已经写完了:日志里有 ✓ built in 43.58s,build/ 目录 506 个文件齐了。报错来自构建后的类型检查,它扫到了 tests/MermaidToExcalidraw.test.tsx 里的 Type '[number, number]' is not assignable to type 'LocalPoint'。测试文件不影响产物,但会污染退出码。
数据存在浏览器本地
画的东西写进 IndexedDB,换浏览器 / 清缓存 / 开无痕窗口都看不到之前的画。要多人协作得另配服务端,这套静态包不带。
反过来说,这也是它轻的理由。没有账号体系,没有后端接口,一个静态服务器就够跑。
从源码到能画图
四步跑起来
yarn install
yarn build:packages
cd excalidraw-app && node ../node_modules/vite/bin/vite.js build
npx http-server build -a 127.0.0.1 -p 5001
静态服务器 0.84 秒就绪,页面到画布可用是 4.35 秒。第一次打开会加载 22.99 MB 的静态资源,之后走浏览器缓存。
| 环节 | 耗时 | 说明 |
|---|---|---|
| 装依赖 | 646 | 秒 |
| 构建 packages | 76 | 秒 |
| 构建应用 | 43.58 | 秒 |
| 静态服务就绪 | 0.84 | 秒 |
| 首屏可画 | 4.35 | 秒 |
第一次打开该做什么
不用配置,直接在画布上按 R 拖一个方框。左侧属性面板立刻展开,能改 6 个设置:描边颜色 / 字体 / 字号 / 文本对齐 / 透明度 / 图层顺序。
画完按 Ctrl+S 存到本地,或者 Ctrl+Shift+E 导出。这两个快捷键在命令面板里都能查到。

画布上的一次实际操作
为了确认它真的能画,我用键盘加鼠标做了一张最小流程图:两个圆角矩形 / 一条箭头 / 两段文字,共 5 个元素。
| 步骤 | 操作 | 结果 |
|---|---|---|
| 1 | 按 R,拖出 200x130 | 圆角矩形 |
| 2 | 按 T,点一下写「白板画流程图」 | 文字元素 |
| 3 | 再按 R 拖第二个框 | 圆角矩形 |
| 4 | 按 A,从左边框拖到右边框 | 带箭头的连线 |
| 5 | 按 T 写「导出 PNG 或 SVG」 | 文字元素 |
| 6 | 画完看页面 | 1015 个 DOM 节点 |
五个元素画完,页面 DOM 从 500 多个涨到 1015 个节点,JS 堆 12.8 MB。这个量级说明画布本身是 Canvas 渲染,DOM 只在工具栏和面板上。
素材库和命令面板
素材库是空的,得自己攒
点右上角的素材库按钮,右侧会滑出 1 块面板,里面 3 个区域:搜索框 / 个人素材库 / 浏览素材库。第一次打开时面板里写着「尚未添加任何项目」,因为它是本地库,需要你把画布上选中的元素拖进去。
这是个容易误会的地方:很多人以为素材库像 Figma 那样自带一堆图标,实际它是给你存自己常用图形的地方。

命令面板能替代记快捷键
Ctrl+/ 打开命令面板,功能按 App / Export / Editor 3 组排开,右边标着快捷键。记不住按键时用它最快,输入框支持搜索。
| 功能 | 快捷键 |
|---|---|
| 导出图片 | Ctrl+Shift+E |
| 保存到本地 | Ctrl+S |
| 复制为 PNG | Shift+Alt+C |
| 深色模式 | Shift+Alt+D |
| 命令面板 | Ctrl+/ |
| 在画布上查找 | Ctrl+F |

导出:PNG 和 SVG 两条路
导出面板给了 4 个开关和 3 档倍率:仅选中 / 背景 / 深色模式 / 包含画布数据,倍率 1x / 2x / 3x。右边是实时预览,改动立刻反映在缩略图上。
底部三个按钮分别是下载 PNG / 下载 SVG / 复制到剪贴板。要贴进文档用 PNG,要放大不糊用 SVG,要快速发给同事用复制。
「包含画布数据」这个开关有副作用。打开之后导出的文件里嵌了场景 JSON,别人重新导入还能继续编辑。发给客户预览时应该关掉,免得把 5 个元素的草稿一起发出去。

性能:4.35 秒首屏,12.8 MB 堆
这个体积在前端应用里算正常。主包 1898235 字节,加上字体和分块一共 22.99 MB,其中 sourcemap 占了一半以上。
| 指标 | 数值 |
|---|---|
| 首屏可画 | 4.35 |
| JS 堆 | 12.8 |
| DOM 节点 | 1015 |
| 画布尺寸 | 1440x900 |
| 主包字节 | 1898235 |
| 5 个元素 | 5 |
12.8 MB 的堆在同类应用里偏低,原因是它把渲染交给了 Canvas,没有用 DOM 堆图形。元素再多也不会让 DOM 暴涨,这一点在画几十个框的架构图时差别明显。
这个离线包里装了什么
自己构建的好处是可以把整包压到 49.7 MB 发出去:静态产物 383 个文件 22997644 字节,便携 node.exe 93381448 字节,一个 40 行的静态服务器,三个 bat。
| 内容 | 体积 | 作用 |
|---|---|---|
| app/build | 22997644 | 字节,383 个文件,去掉 sourcemap |
| node.exe | 93381448 | 字节,只用来跑静态服务 |
| serve.cjs | 1200 | 字节,127.0.0.1 上开 5050 |
| 压缩包 | 52161394 | 字节 |
sourcemap 占了构建产物的一半。它在生产环境只对调试有用,删掉之后 47.5 MB 变成 22.99 MB,浏览器该有的功能一个不少。
为什么不用双击 index.html
它是单页应用,路由和 service worker 都按 HTTP 协议写。用 file:// 打开会出现空白页或者资源 404,控制台里是 Failed to load module script 这类报错。
所以包里带了一个最小的 node 服务,只做三件事:读文件 / 猜 Content-Type / 找不到路径就回 index.html。不用装依赖,不用 npm。
换端口和更新
默认 5050,想换端口改 2-启动.bat 里那两个 5050 就行,serve.cjs 会读命令行参数。前面挂反向代理时注意别把路径改掉,它把根路径当应用根。
更新版本有个坑:service worker 会缓存旧资源。替换 build 目录之后如果看到的还是旧界面,按 Ctrl+Shift+R 强刷一次,或者清掉站点数据。
几个真踩过的报错
| 症状 | 原因 | 处理 |
|---|---|---|
| vite build 报找不到包 | packages 还没构建 | 先跑 build:packages |
| 构建退出码 2 | 测试文件 TS2322 | 产物已生成,可忽略 |
| 打开是空白页 | 用了 file:// 协议 | 起静态服务器访问 |
| 改了代码界面没变 | service worker 缓存 | Ctrl+Shift+R 强刷 |
| 端口被占用 | 5050 已有进程 | 换端口或先停止 |
第一条最费时间:直接跑 vite build 时它会去找 @excalidraw/excalidraw 的 esm 产物,没构建过就是空的,报错信息只提包名不提这一步。
官方站点和这套离线版的取舍
官方站点打开就能用,还能保存到 Excalidraw+ 和多人协作。这套离线包没有后端,2 个能力用不了:多人协作和云端保存,换来的是内网可用和数据不外发。
| 能力 | 官方站点 | 离线包 |
|---|---|---|
| 打开即用 | 要联网 | 本地 4.35 秒 |
| 多人协作 | 支持 | 不支持 |
| 云端保存 | 支持 | 只有浏览器本地 |
| 数据外发 | 经过对方服务器 | 不出这台机器 |
界面右上角的「Try Excalidraw+ 14-day free trial」是官方付费版的入口,点进去要注册。离线包里这个按钮还在,但点了没网就停在加载。
同一张图,四个工具各做一遍
讲取舍之前先把图做出来。同一张最小流程图,两个圆角矩形 / 一条箭头 / 两段文字,四个工具各做一遍,量的是「打开到能看见这张图」的秒数。四个数里最快的 1.67 秒,最慢的 4.35 秒。
三个白板比界面响应,Mermaid 比渲染速度。它没有画布,图是从文本算出来的,两种数字放一列里比不出东西,拆成两张表。
| 工具 | 第 1 次 | 第 2 次 | 第 3 次 | 第 4 次 | 形态 |
|---|---|---|---|---|---|
| draw.io 32.6.1 | 1.67 | 1.68 | 1.70 | — | 桌面版 exe |
| tldraw 在线版 | 3.15 | 1.97 | 3.05 | 1.95 | 浏览器 |
| Excalidraw 离线包 | 4.35 | — | — | — | 静态包加 node 服务 |
三个数字都是「进程或页面起来到画布能画」为止,不是标题栏出现的时间。draw.io 跑了三轮,分别是 1.67 秒、1.68 秒、1.70 秒,稳定得像个开机自检。tldraw 冷启动两次是 3.15 秒和 3.05 秒,缓存命中后掉到 1.97 秒和 1.95 秒。

draw.io 快 2.5 倍,差在加载路径
1.70 对 4.35,差了两倍多。原因不在代码写得好不好:draw.io 从本地磁盘读 asar 包,Excalidraw 离线包要先起一个 http 服务,再让浏览器拉 22.99 MB 静态资源,中间多一层协议和缓存协商。
拿这个差距下结论之前先看自己怎么用。一天开十次图,4 秒和 1.7 秒是能感觉到的;一周画一张,两个都在忍耐范围内。
Mermaid 的 196156 字节里,字体占 167076
同一张图,draw.io 导出的 SVG 是 24045 字节,Mermaid 是 196156 字节,差 8.2 倍。看着像 Mermaid 效率低,实际差在字体。
| 项目 | draw.io 32.6.1 | Mermaid CLI |
|---|---|---|
| 源文件字节 | 1037 | 63 |
| SVG 字节 | 24045 | 196156 |
| 体积相差倍数 | 1 | 8.2 |
| 嵌进 SVG 的字模 | 不嵌 | 167076 |
| 不嵌字体的 SVG | 不适用 | 29080 |
| 不嵌字体后的倍数 | 不适用 | 6.7 |
| PNG 字节 | 20733 | 14652 |
| 单次导出耗时 | 1.21 | 3.62 |
| 依赖体积 | 不适用 | 428 MB |
| 安装包字节 | 180210310 | 不适用 |
换一个参数再导一次,体积掉到 29080 字节,只剩原来的一成半。196156 减 29080 得 167076,这部分是把字模数据塞进了 SVG。
mmdc -i same.mmd -o out.svg # 196156 字节
mmdc -i same.mmd -o out.svg --no-font-embed # 29080 字节
嵌字体的好处是文件传到别人手里,字形不会掉。坏处是体积大 6.7 倍,塞进网页以后,每份拷贝都要驮着这些字模数据。放静态站点上,页面自己已经加载了中文字体,加 --no-font-embed 更划算。
Mermaid 慢在起浏览器,不在画图
三张图一次跑完 4015 毫秒,单张三轮是 3762 / 3639 / 3619 毫秒。三张的 SVG 分别是 196150 字节、189975 字节、197042 字节,体积跟着图里的内容量走。多出两张只加了不到半秒,命令行版本每次调用都要拉起一个无头 Chrome,那 3.62 秒基本是浏览器启动的开销。要批量出图,全部塞进一个文件里跑,别写循环调三次。
# 单张三轮 3762 / 3639 / 3619 毫秒;三张一批 4015 毫秒
# 三张产物 196150 / 189975 / 197042 字节
mmdc -i same.mmd -o out.svg # 196156 字节
mmdc -i same.mmd -o out.svg --no-font-embed # 29080 字节
这套 Node 依赖装下来 428 MB,比 draw.io 整个安装包 180210310 字节还大。用它换来的是纯文本源文件,一台机器装一次,之后所有图都靠两行文字算出来。

把出图这件事交给命令行
draw.io 桌面版带命令行导出,这是它比三个在线白板多出来的一块。不用点菜单,一条命令出图,第二轮开始每次 1.21 秒,能塞进构建脚本或者文档生成流程里。
draw.io.exe --no-sandbox -x -f svg -o out.svg same.drawio
draw.io.exe --no-sandbox -x -f png -s 2 -o out.png same.drawio
-x 是只导出不弹窗口,-f 指定格式,-s 2 是两倍放大。同一份文件连跑三次,耗时 4.47 / 1.21 / 1.33 秒,产物都是 24045 字节,一个字节都不差。
输出确定性这件事被低估了。同一份文件连跑三次,每次都是 24045 字节,才能把产物放进 git 里比对,或者用哈希确认线上图跟源码是不是同一版。手绘风格的白板做不到。
第二次快三倍,快在文件缓存
整包解压成 72 个文件用了 2.40 秒,首次导出那 4.47 秒里有一半花在加载 asar 包。第二轮开始这些文件进了系统缓存,剩下 1.21 秒基本就是 Electron 起进程的开销,第三次 1.33 秒。
# 首次 4.47 秒 → 24045 字节;第二次 1.21 秒;第三次 1.33 秒
# PNG 两倍图 2.18 秒 → 20733 字节;解压 72 个文件 2.40 秒
draw.io.exe --no-sandbox -x -f svg -o out.svg same.drawio
批量出十张图就把启动开销合并成一次,别写成十次命令行调用,剩下的时间几乎都是渲染本身。
源文件字节:63 对 1037
同样一张图,Mermaid 的源文件 63 字节,draw.io 的 mxfile 1037 字节。这两个数字决定了它们在版本管理里的手感。
Mermaid 那边就是两行文本,加起来 63 字节。改标题等于改一行文字,diff 里一眼看到哪几个字变了。draw.io 的 XML 里每个形状带完整样式串,挪一个框会让坐标和样式一起变,diff 读起来累,好处是改完不会跑版。
Excalidraw 的场景 JSON 没做这一项对比,导出面板是手动点的,没跑成自动化,这一栏空着。
四种工作流对应四种用法
把秒数放一边,真正的分界线是「图从哪来、以后改不改」。
| 你的情况 | 合适的工具 | 理由 |
|---|---|---|
| 架构图要进文档,改十几次 | draw.io | 图形能吸附对齐,改一处不动其他 |
| 图要跟代码放在一个仓库 | Mermaid | 纯文本,diff 能看出改了哪一行 |
| 开会时随手画两笔发群里 | tldraw | 3 秒进画布,不用装 |
| 内网,草稿不能出网 | Excalidraw 离线包 | 整包在本地跑,只写浏览器存储 |
要反复改图就选 draw.io
draw.io 的图形带吸附点和连接关系,拖动方框时箭头跟着走。
Excalidraw 的箭头也跟手,但线条是手绘抖动算法画的,两个框对齐时边缘会有一两像素的错位感。
它的文件是纯文本 XML,那张 5 元素图存下来就是一份轻量文本。扔进 git 里 diff 是干净的,改了哪个坐标一目了然。
图要跟代码一起提交,选 Mermaid
源文件两行写完这张图,改标题就是改一行文字。文档站和仓库 README 里那种自动生成的流程图基本都是它。
代价是没有画布。位置由布局算法算出来,想挪一个框得加 rank 或者换方向声明。
图长到二十来个节点以上,自动布局开始绕线,这时手工调不如换 draw.io。
tldraw 的价值在协作,不在离线
它打开最快,3 秒进画布,画完能直接发链接给别人。代价是内容都在对方服务器上,断网就用不了,界面右上角那个「登录以分享」是它的主线功能。
比起 Excalidraw,它的工具收得更紧,圆角、样式和字号都有固定档位,画出来的东西整齐。要自定义颜色得开右侧的样式面板调。
离线包的位置在哪里
四个工具里只有 Excalidraw 离线包要自己动手构建,也是唯一能把整套东西关在内网里的。那 4.35 秒换来的是一份可审计的静态资源,不连外网也能画。
想要个白板还有更省事的路:draw.io 的 exe 解压就能跑,72 个文件,1.7 秒打开,比构建一套几百 MB 的依赖省事得多。这套离线包值得做的场景只有一个,机器不让装软件,只能跑浏览器和 node。
什么情况下别装
它是给「偶尔要画张图」的人用的。每天要画图,或者需要图层管理和版本历史的人,专业的矢量工具更合适。
| 你的情况 | 结论 |
|---|---|
| 偶尔画架构图 / 流程图 | 合适 |
| 要多人实时协作 | 不合适,静态包不带后端 |
| 图要打印、要精确到毫米 | 不合适,手绘风格不适合制图 |
| 只想要个白板截图 | 不合适,官方站点三秒就能用 |
| 内网离线环境 | 合适,这套包就是为这个做的 |
还有一点:它的手绘线条是靠算法抖动出来的,同样的矩形画两遍线条不完全一样。要严格对齐的图,把属性面板里的 手绘风格 关掉再画。
至于要不要自己构建,看需求。官方站点打开就能用,构建这套的价值在于内网 / 离线 / 不想让草稿经过别人服务器。







