VS Code 配置 PlantUML:本地渲染、中文修复与图即代码 📅 发布时间:2026/9/16 22:55:27 👁 浏览次数: 1. 为什么我在 VS Code 里配置 PlantUML而不是继续用拖拽工具前几年做系统梳理的时候我一直用那些拖拽式的画图软件。鼠标点一点、连个线、调调框的大小看起来挺直观。真正让我下决心换掉它的是一次需求评审会上定稿的架构图存在共享盘里两周后有人改了其中的模块名但没同步更新那张图。等到下个迭代再拉出来讲图上写的还是旧的服务名底下坐着的人一半在猜、一半在翻代码会议后半段全耗在到底以哪个为准上。后来我开始在 VS Code 里配置 PlantUML 环境把图变成纯文本文件。这件事的核心变化不在于画得更好看而在于图变成了可以被 diff、被 review、被回滚的东西。一个.puml文件本质上就是几十行文本谁改了哪个参与者、哪个箭头git diff里一清二楚跟你审查代码没什么两样。这跟拖拽工具产出的一坨二进制或者一大段 XML 完全不是一个量级的可维护性。如果你属于下面这几类人这套组合大概率能省下你不少时间需要频繁更新架构图和时序图的研发同学写设计文档、接口文档时总要贴图的技术写作者带团队做方案评审、希望图能跟着代码一起进仓库的技术负责人以及做毕业设计、课程作业需要画 UML 的学生。反过来讲如果你只是偶尔画一张流程图贴在 PPT 里一年不超过五次那老老实实开个在线编辑器拖两下就完事了专门折腾本地环境属于杀鸡用牛刀。这篇文章我会把整个配置过程拆到能直接抄的程度包括那些教程里通常不讲、但实际一定会绊你一脚的地方——尤其是 Java 这条隐形的命脉和中文标签渲染成方块的坑。2. 装扩展之前先把 Java 这条命脉理顺2.1 PlantUML 的本体其实是一个 Java 程序这是很多人第一次接触时最大的认知偏差。你在扩展市场里搜到的那个 PlantUML 插件它本身只是个外壳——负责解析你编辑器里的文本、调用渲染引擎、把生成的图片贴回预览面板。真正的渲染逻辑跑在一个叫plantuml.jar的 Java 程序里。也就是说没有可用的 Java 运行时扩展装得再漂亮也出不来图。我用外壳 引擎这个说法是有意的。理解了这层结构后面所有的报错你都能对上号预览面板一直转圈可能是引擎没启动提示找不到 dot是引擎在处理非时序图时需要外部的布局工具中文变成方块是引擎所在的那个 JVM 找不到中文字体。每一条都指向引擎而不是指向 VS Code。所以配置的第一件事不是打开扩展市场而是先把 Java 装好并让它可被调用。2.2 JDK 还是 JRE版本具体怎么挑从跑 PlantUML 的角度理论上只要有 Java 运行时就够了JRE 也能用。但现实里我建议直接装 JDK理由很实在第一你机器上大概率还有别的工具要用到javac装了 JDK 就不用装两遍第二某些版本的 PlantUML 在启动时会做一些自检JRE 的裁剪版本偶尔会缺类。版本上我这些年试下来的结论是优先选 LTS 版本11 或者 17 起步17 是我目前的主力。老的 Java 8 也不是不能跑但新版本 PlantUML 对 8 的支持在逐步收紧而且 Java 8 安装包在配置 PATH 时的行为和后续版本略有差异容易在环境变量上踩坑。至于最新的非 LTS 版本除非你有别的原因必须用否则没必要出问题时网上能对上的案例少。安装路径上有个小建议别装到带空格或者中文的目录里比如C:\Program Files\Java\...里那个空格在某些脚本调用场景下会带来转义麻烦。我自己习惯装在C:\dev\jdk-17这种干净路径下后面写配置的时候心里也踏实。2.3 验证 Java 是否真的可被 VS Code 看见装完之后别急着往下走有三件事必须逐一确认顺序不能乱。第一在系统环境变量里设置JAVA_HOME指向 JDK 根目录然后把%JAVA_HOME%\bin追加到PATH里。注意是追加上bin目录不是把 JDK 根目录本身塞进 PATH这两者搞混是最常见的低级错误。第二重开一个命令行窗口执行java -version javac -version两条都要有输出。如果java有输出而javac没有说明 PATH 里可能指向的是某个残留的 JRE如果两条都没有那 PATH 就没生效检查一下是不是改完没重启终端。第三也是最容易被忽略的一步从命令行启动 VS Code。Windows 上在终端输入code就能拉起编辑器macOS 上如果没配命令行工具直接在应用里改完环境变量后完全退出 VS Code 再重新打开也行。为什么强调这一步因为 VS Code 继承的是它启动那一刻的环境变量。你在装 Java 之前就开着 VS Code然后再去改 PATH编辑器是感知不到的。这时候不管你怎么重启扩展、重装插件它拿到的还是旧环境报错依旧是找不到 java。这个坑我自己踩过也见过太多人在论坛上问同样的问题。3. 扩展怎么选、第一次预览为什么不出图3.1 同类扩展的取舍逻辑市场中搜plantuml排在前面的有好几个。我长期用的是 jebbs 的那个 PlantUML 扩展它的命令体系和配置项跟我下面要讲的完全对得上。选它的理由有三点活跃度高配置项足够细能覆盖从本地渲染到批量导出的完整链路导出格式给得全PNG、SVG、PDF 都能出命令行和配置项的设计跟plantuml.jar的原生命令行参数能映射上你理解了一个另一个自然就通了。市面上还有一些偏轻量的预览插件它们的好处是装完即用不用配 Java因为它们默认走在线渲染服务。代价是你的图要发到外部服务上去渲染涉及内部系统结构、接口名、甚至业务流程的图我一般不这么干。而且断网的时候整个插件就废了。这就引出了 PlantUML 的两种渲染模式后面第 5 节我会展开讲配置这里先说结论渲染模式依赖适用场景主要代价本地渲染Local本机 Java plantuml.jar内部系统图、涉密内容、离线环境、批量导出首次要配环境占本机内存在线渲染Server网络可达的外部渲染服务临时画个公开的示意图、快速验证语法内容外发断网不可用我的建议很明确只要你的图涉及工作中的系统一律走本地渲染。前期多花二十分钟配环境换来的是长期不用为内容外流担心。3.2 安装后必须立刻改的三个配置项装完扩展直接按AltD预览多半是转圈或者报错。先别慌打开设置Ctrl,搜plantuml把这三项确认一遍。第一个是plantuml.render设成Local。很多扩展安装后默认是在线模式你不改它它就一直往外部服务发请求在受限网络环境下就是无限转圈。第二个是plantuml.jar指向你本地的plantuml.jar文件路径。这个 jar 你可以从 PlantUML 项目主页下载放到一个固定位置比如C:\dev\plantuml\plantuml.jar。放好之后就别再挪了路径写进配置里挪一次改一次很烦。第三个是plantuml.java如果你的java已经在 PATH 里一般不用填但如果系统里有多个 Java 版本我强烈建议这里显式写死一个完整路径避免扩展调到那个你不期望的版本上。配置写进settings.json大概长这样{ plantuml.render: Local, plantuml.jar: C:\\dev\\plantuml\\plantuml.jar, plantuml.java: C:\\dev\\jdk-17\\bin\\java.exe, plantuml.commandArgs: [ -Dfile.encodingUTF-8, -Djava.awt.headlesstrue, -Xmx1024m ] }-Dfile.encodingUTF-8保证读取.puml文件时按 UTF-8 解析-Djava.awt.headlesstrue让 JVM 在无图形界面环境下也能正常渲染服务器和容器里跑批量导出时必须加-Xmx1024m是给渲染引擎的内存上限图一复杂就容易吃内存默认值往往不够。3.3 第一次预览失败时的逐层排查链路我习惯按从下往上的顺序查这样不会乱。第一层Java 是否可用。在 VS Code 的集成终端里执行java -version注意是集成终端不是你自己另开的窗口因为集成终端继承的才是编辑器的那套环境。这一步没过回到第 2 节。第二层jar 是否可读。检查plantuml.jar配置的路径下文件确实存在且文件没坏。快速判断办法是命令行跑一次java -jar plantuml.jar -version能打印版本信息就说明 jar 本身没问题。第三层渲染模式是否真的切到了 Local。有时候你改了用户设置但工作区设置里有一份覆盖配置实际生效的不是你改的那份。打开命令面板搜Open Workspace Settings看一眼。第四层才是语法问题。PlantUML 的语法错误会在预览区下方给出行号提示这类错误反而是最好解决的。把这条链路走一遍九成以上的预览不出来都能定位到具体原因。我遇到过的真实案例是同事改了plantuml.jar的配置但那次是改在工作区设置里换了个项目打开就失效了他一直以为是扩展抽风。搞清楚设置的作用域能省下很多无谓的重装。4. Graphviz 与非时序图为什么有的图只画了一半4.1 哪些图依赖 dot哪些不依赖这是个非常关键但极少被讲清楚的点。PlantUML 内部的图形大致分两类时序图sequence diagram这类有明确时间轴的图PlantUML 自己就能布局不依赖外部工具而类图、组件图、部署图、状态图、活动图这些需要做**图布局graph layout**的图PlantUML 会去调用一个叫 Graphviz 的工具通过它的dot可执行文件来计算节点位置。这就解释了那个经典现象画个时序图好好的一画类图就报Dot executable does not exist或者Cannot find Graphviz。不是你的语法错了是引擎少了一条腿。所以我的建议是把 Graphviz 一起装上反正是一次性的事。装完之后 PlantUML 能找到dot前面说的那几类图就都能渲染了。4.2 装上 Graphviz 之后怎么确认它被认到安装 Graphviz 时有一个选项是添加到系统 PATH务必勾上。装完重开终端验证dot -V正常会打印出版本号比如dot - graphviz version 9.x.x。注意是大写-V小写-v会输出一大堆调试信息刷屏。验证通过后回到 VS Code 里一定要完全退出编辑器再重新打开让新进程重新读一次环境变量。然后随便写个类图试一下startuml class Order { String orderId create() } class Payment { pay() } Order -- Payment : 关联 enduml能出图就说明整条链路通了。如果还是提示找不到 dot那就需要在plantuml.commandArgs里显式指定路径plantuml.commandArgs: [ -Dfile.encodingUTF-8, -Djava.awt.headlesstrue, -DGRAPHVIZ_DOTC:\\dev\\graphviz\\bin\\dot.exe ]Windows 上路径里的反斜杠要写成双反斜杠这是 JSON 转义的要求很多人在这里写单斜杠导致配置整体解析失败设置页面直接标红。4.3 一个容易被当成渲染慢的问题有段时间我画组件图每次预览都要等四五秒一度以为是电脑不行。后来发现是-Xmx给得太小图稍微复杂一点就频繁触发垃圾回收。把内存上限从默认调到我常用的 1024MB 之后同样的图基本一秒内出预览。另一个提速手段是把预览格式从 PNG 换成 SVG。SVG 是矢量图渲染时不需要做栅格化那一圈计算而且放大不糊放进文档里也清晰。我的做法是预览用 SVG导出时候再按需转格式。5. settings.json 里的关键参数逐条拆开讲5.1 渲染模式与 jar 路径的两组配置前面提过plantuml.render和plantuml.jar这里补充两个相关的。plantuml.server只在渲染模式为 Server 时有意义填的是外部渲染服务的地址。我不推荐日常用但有一种场景例外临时在别人的机器上快速验证语法不想装环境。用完记得改回来。plantuml.commandArgs是我花时间最多的一个配置项因为它直接决定渲染引擎怎么启动。除了前面说的编码、headless、内存、Graphviz 路径之外还有一个-Duser.language值得提一句。在部分环境下JVM 的区域设置会影响文本断行和字体回退行为如果你的图里中英文混排偶尔会在换行位置出现诡异的断裂显式指定一下能规避。5.2 导出相关的配置决定了你后期省不省事如果你打算把图导出成文件存进文档目录下面几个配置值回票价plantuml.exportFormat指定导出格式可选png、svg、pdf等。我一般设成svg。plantuml.exportOutDir指定导出目录。这里有个习惯性的做法值得推荐把它设成仓库里一个专门的目录比如docs/diagrams然后把它加进.gitignore。因为你只想要.puml源文件进版本库导出产物每次都能重新生成没必要让它们污染提交记录。这一点我是被坑过的——有一阵子每次提交都夹带一堆变更了的 PNGdiff 全是二进制review 的时候根本看不出改了什么。plantuml.exportSubFolder控制是否按源文件的目录结构在导出目录下建子文件夹。源文件分散在多个模块目录里的时候打开它能省掉自己整理的一步。plantuml.previewAutoUpdate建议保持开启边写边看比手动刷新舒服太多。但要注意如果图特别大每次敲字都触发渲染会卡这时候可以临时关掉改完再开。plantuml.includepaths是配合后面第 6 节的拆分方案用的这里先记住有这个东西。5.3 中文标签变成方块的根因和字体配置这是我见过提问频率最高的问题没有之一。现象很统一英文的类名、方法名显示正常一换成中文就变成一排小方块或者问号。根因不在 PlantUML也不在 VS Code而在渲染引擎所在的 JVM 找不到能显示中日韩字符的字体。默认字体是个西文字体CJK 字符在它里面没有对应的字形系统就只好画一个占位方框。解决办法是在图里显式指定字体startuml skinparam defaultFontName Microsoft YaHei skinparam defaultFontSize 14 skinparam dpi 120 class 订单 { 创建() } endumlWindows 上可用Microsoft YaHei微软雅黑或者SimHei。macOS 上换成PingFang SC。Linux 服务器上通常是WenQuanYi Micro Hei或者Noto Sans CJK SC。这里有个必须提醒的点字体名字必须和系统里实际注册的字体名一致差一个字就静默失败还是出方块。Linux 环境下的调试办法是执行fc-list :langzh看看系统里到底装了哪些中文字体把输出的第一个字段抄进配置里。另一个更容易被忽视的情况是你本地 Windows 上好好的放进容器里批量导出就全是方块。原因是容器镜像里根本没装中文字体。这时候得先装字体包再让 JVM 能用上。这个坑我在做文档流水线的时候踩得很实本地调试两小时没复现一上流水线就炸。对于大团队我建议把字体设置和配色一起抽到一个公共文件里所有图都!include它。下一节就讲这个。6. 把 .puml 当成代码来管理拆分、复用与评审6.1 用 include 把公共样式沉淀下来图一多你一定会遇到改了配色要改二十个文件的窘境。解决办法是把样式抽出来。建一个style.puml style.puml skinparam defaultFontName Microsoft YaHei skinparam defaultFontSize 14 skinparam dpi 120 skinparam shadowing false skinparam roundcorner 8 skinparam ArrowColor #4A6FA5 skinparam classBackgroundColor #F4F7FB然后在每张图的开头引用它startuml !include ../common/style.puml class 用户服务 class 订单服务 用户服务 -- 订单服务 enduml注意相对路径是相对于当前.puml文件本身而不是相对于 VS Code 打开的工作区根目录。这一点很多人搞混导致本地单独打开某个文件能预览放到整个项目里就报 include 失败。如果你确实需要基于一个固定基准点解析路径就在plantuml.includepaths里加一条绝对路径让引擎多几个查找位置。还有个语法细节!include和!include_once的区别。前者每次都插入后者只插一次。如果你的公共文件里定义了一堆!define宏重复 include 会导致宏重定义报错这时候用!include_once更稳妥。6.2 主题和自定义皮肤参数怎么选PlantUML 内置了一批主题用法是一行!theme cerulean位置要放在所有skinparam之前否则会被覆盖。刚上手的时候用内置主题是性价比最高的选择省掉自己调色的一堆时间。但我个人在中后期更倾向于自己控制原因是内置主题的配色偏艳丽放进技术文档里容易抢正文的注意力。我的习惯是只保留几个必要的skinparam字体、箭头颜色、圆角、去阴影其他一律用默认。技术图的价值在于把关系表达清楚装饰越少越好。有一个skinparam我需要单独说skinparam monochrome true。它能一键把所有图变成黑白线条风格打印友好、在低质量投影仪上也清晰。做正式评审材料的时候我经常临时加上这一行效果比调半天颜色好得多。6.3 让图跟着代码走的那套协作习惯环境配好之后真正的收益来自使用习惯。我坚持三条。第一图放在离代码最近的地方。哪个模块的架构图就放在那个模块的docs目录下而不是统一丢到一个跟代码毫无关联的文档库里。这样改代码的人更容易顺手把图一起改了而且 review 的时候两边的改动在一个上下文里。第二把.puml纳入 code review。既然它是文本就应该被审。改动一个箭头方向可能意味着依赖关系的调整这种信息值得在 PR 里被看到。我见过团队在 PR 模板里加一条架构变更是否已更新对应图执行一段时间后图和实现的漂移明显变小。第三给.gitattributes加两行把 puml 文件标记为文本并强制 LF 换行避免不同操作系统上提交时整文件 diff*.puml text eollf这个动作看起来很小但能避免只改了一行却显示整个文件都变了这种让人抓狂的情况。7. 命令行批量导出与文档流水线7.1 直接调用 jar 的几种常用姿势因为渲染引擎就是那个 jar你完全可以用命令行绕过 VS Code。这在生成文档、跑 CI 的时候特别有用。导出一张图为 SVGjava -jar plantuml.jar -charset UTF-8 -tsvg -o ../out docs/diagrams/arch.puml把整个目录下所有.puml批量转成 PNGjava -jar plantuml.jar -charset UTF-8 -tpng -o ./build/diagrams ./docs/diagrams只做语法检查不生成图CI 里非常有用java -jar plantuml.jar -charset UTF-8 -checkonly ./docs/diagrams-checkonly返回非零退出码就说明有语法错误直接在流水线里卡住提交能防止带着错误的图被合进主干。我现在的习惯是在 pre-commit 钩子里跑一次-checkonly比等到 review 时被人指出来舒服多了。-charset UTF-8这个参数强烈建议每次都带上尤其是 Windows 环境。它决定 jar 读文件时用什么编码解析不指定的话默认走系统编码中文注释和中文标签都可能出问题。这个参数和前面 VS Code 配置里的-Dfile.encodingUTF-8是两件事一个管读文件一个管 JVM 内部两个都要有。7.2 写个脚本处理多模块目录项目一大.puml分散在各个子目录里一条命令搞不定的时候就需要脚本#!/usr/bin/env bash set -euo pipefail JAR./tools/plantuml.jar SRC./docs OUT./build/diagrams mkdir -p $OUT find $SRC -name *.puml -print0 | while IFS read -r -d file; do echo rendering: $file java -jar $JAR -charset UTF-8 -tsvg -o $OUT $file done echo done有两点值得说明。set -euo pipefail让脚本遇到任何一条命令失败就整体停下避免个别图报错但脚本还在欢快地跑最后你以为全成功了。-print0配read -d 是为了正确处理文件名里带空格的路径这个细节在 Windows 生成的目录里特别常见。7.3 把出图这一步塞进文档构建流程如果你的文档是用静态站点工具生成的完全可以把上面的脚本挂到构建命令前面。这样每次发布文档图都是最新渲染的不存在文档里贴的还是三个月前的图这种情况。这里我要强调一个原则导出产物不要进版本库。源文件进库产物在构建时生成。前面提到的exportOutDir加.gitignore就是这个思路。这样做的好处是仓库干净、diff 有意义坏处是别人 clone 下来得先跑一次构建才有图。对技术同学来说这个门槛完全可以接受。8. 我踩过的坑与日常效率技巧8.1 常见报错对照表把这些年遇到的典型问题整理成一张表方便你对着症状找原因报错或现象真实原因处理方式Cannot find java/ 预览一直转圈VS Code 未继承新配置的 PATH完全退出 VS Code从终端code重新启动Dot executable does not exist未装 Graphviz 或 PATH 未生效安装并勾选加入 PATH重启编辑器中文显示为方块或问号JVM 找不到中文字体skinparam defaultFontName指定系统已注册的中文字体Error line N并指向某行PlantUML 语法错误从提示行往上找通常是上一行少了结尾符号类图渲染极慢内存上限过小频繁 GC调大-Xmx预览格式改为 SVG改工作区设置后换项目失效用户设置与工作区设置作用域混淆统一改用户设置或明确只在该项目内生效容器里导出全是方块容器镜像未安装中文字体镜像里安装 CJK 字体包后重新构建8.2 几个明显提升体验的小设置先说预览格式。默认预览是 PNG我改成 SVG 之后最直观的感受是清晰度和响应速度都上来了。改法是plantuml.previewFormat设成svg。再说代码片段。PlantUML 的图开头结尾都是固定套路我给自己配了几个 snippet输入pseq就展开成一个带样式的时序图骨架省掉每次手打skinparam的工夫。配置放在 VS Code 的用户代码片段文件里{ PlantUML Sequence: { prefix: pseq, body: [ startuml, !include ../common/style.puml, autonumber, , actor 用户, participant 服务A, database 数据库, , 用户 - 服务A : 请求, 服务A - 数据库 : 查询, 数据库 -- 服务A : 结果, 服务A -- 用户 : 响应, enduml ] } }还有个小技巧把AltD记住这是预览当前图的默认快捷键。多图分块的时候光标停在哪个startuml块里预览的就是哪张图不用来回切文件。8.3 关于要不要一次配到位的经验我见过两种极端。一种是图省事装个在线渲染的插件一直用到某天发现图里的内部服务名出现在了不该出现的地方另一种是过度工程化一上来就搭流水线、写脚本、抽公共库结果自己的图一共就三张配置比图本身还复杂。我的实际体会是先跑通最小闭环再按痛点加东西。最小闭环就是 Java jar 扩展本地渲染出一张图。用上一两周如果你发现自己开始重复写同样的样式就去抽公共文件如果发现自己每次提交都夹带二进制产物再去配导出目录和 gitignore如果团队开始因为图不同步吵架再上流水线和检查。每一步都由真实的不适感驱动配置才有意义。至于那个被反复问到的为什么我的图渲染不出来我的排查顺序始终是先怀疑环境变量有没有被编辑器继承再怀疑外部依赖Graphviz、字体在不在最后才怀疑语法。按照这个顺序绝大多数问题在第二步之前就能定位。这套环境我前后在 Windows、macOS 和容器里都配过一轮真正难的部分从来不是 PlantUML 的语法而是让那个 Java 程序在各种环境里都能顺利找到它需要的东西。