PlantUML CLI 高级用法:批量渲染、stdin/stdout、CI 集成、增量构建
多数人只会 plantuml file.puml——但 plantuml 命令行能做到的事比想象的多得多。这一篇整理「脚本小子」级别用法:批量、CI、监控、管道、自定义预处理。
命令行最小知识
1
| plantuml [options] file-or-files
|
常用选项:
| 选项 |
含义 |
-tsvg / -tpng / -tpdf / -tlatex |
输出格式 |
-o dir |
输出目录 |
-I path |
!include 搜索路径 |
-c |
共用 SVG 不带 CSS |
-DPLANTUML_CONFIG=... |
加载全局皮肤文件 |
-thread N / -no-thread |
线程数(默认 JVM 核心数) |
-checkonly |
只校验,不渲染 |
-pipe |
从 stdin 读 / 输出到 stdout |
-stdlib |
输出标准库路径 |
-language |
列出支持的语言 |
1. 单文件管道:从 stdin 读
1 2 3
| echo "@startuml Alice -> Bob: hi @enduml" | plantuml -pipe -tsvg > out.svg
|
实战:渲染一段内存里的 puml 字符串,不用写临时文件——配合 curl 拉远程 source 或 jq 解析 JSON 里的 puml block。
2. 渲染整个目录
1
| plantuml -tsvg -o rendered/ docs/diagrams/
|
渲染 docs/diagrams 目录下所有 .puml 文件到 rendered/。
缺点:会递归处理所有子目录,包括你不想要的。
控制递归
1
| plantuml -tsvg -recursive=false -o rendered/ docs/diagrams/*.puml
|
不用递归时显式列出文件列表。
3. 批量并发
1 2 3 4 5
| plantuml -tsvg -thread 8 -o rendered/ docs/diagrams/*.puml
ls docs/diagrams/*.puml | xargs -P 4 -I{} plantuml -tsvg {} -o rendered/
|
注意:xargs -P N 调 N 个 plantuml 进程,每个都是 JVM——4 进程 = 4 × JVM 启动开销。用 plantuml 自带的多线程模式更划算。
性能调优
1 2
| plantuml -tsvg -thread 3 -o rendered/ docs/diagrams/*.puml
|
4. stdin → 多个输出格式
1
| cat diagram.puml | plantuml -pipe -tsvg -o /tmp/pipe/
|
-pipe + 输出目录:植物uml 自动产生 diagram.svg 在 /tmp/pipe/。
但多个输出格式用 -pipe 不行——只能一次一种。
一次渲染多格式
1 2 3
| for fmt in svg png pdf; do plantuml -t${fmt} -o "rendered-${fmt}" diagram.puml done
|
5. 只校验不渲染(CI 友好)
1
| plantuml -checkonly diagram.puml
|
exit code 0 成功;非 0 失败——CI 友好。
实际 CI 校验流程
1 2 3 4 5 6 7 8 9 10
| #!/bin/bash set -e fail=0 for f in $(find docs -name '*.puml'); do if ! plantuml -checkonly "$f"; then echo "❌ $f 语法错" fail=1 fi done exit $fail
|
比 -tsvg 快:只解析不渲染,CI pipeline 里 1 分钟跑完 100 张图。
6. 增量构建:复用旧图
1 2
| plantuml -tsvg -o rendered/ docs/diagrams/*.puml
|
自建增量:
1 2 3 4 5 6 7 8
| #!/bin/bash
for puml in docs/diagrams/*.puml; do svg="rendered/$(basename "$puml" .puml).svg" if [ ! -f "$svg" ] || [ "$puml" -nt "$svg" ]; then plantuml -tsvg "$puml" -o rendered/ fi done
|
更聪明:记住上次 hash:
1 2 3 4 5 6 7 8 9 10 11 12 13
| store=".cache/puml-hashes.json" mkdir -p .cache [ -f "$store" ] || echo '{}' > "$store"
for puml in docs/diagrams/*.puml; do name=$(basename "$puml" .puml) cur_hash=$(md5sum "$puml" | cut -d' ' -f1) prev_hash=$(jq -r ".\"$name\" // \"\"" "$store") if [ "$cur_hash" != "$prev_hash" ]; then plantuml -tsvg "$puml" -o rendered/ jq --arg n "$name" --arg h "$cur_hash" '.[$n]=$h' "$store" > "$store.tmp" && mv "$store.tmp" "$store" fi done
|
依赖图变化也会触发(让 !include 子文件被追踪):
1 2 3 4 5 6 7 8
| hash_inputs() { local puml="$1" cat "$puml" grep -h '!include' "$puml" | awk '{print $2}' | while read -r inc; do [ -f "inc/$inc" ] && cat "inc/$inc" done | md5sum }
|
7. 监控文件:自动重新渲染
fswatch(macOS)
1
| fswatch -o docs/diagrams/ | xargs -I{} plantuml -tsvg -o rendered/ docs/diagrams/*.puml
|
每次文件变动都重新渲染。
inotifywait(Linux)
1 2 3
| while inotifywait -e close_write docs/diagrams/; do plantuml -tsvg -o rendered/ docs/diagrams/ done
|
实用 dev workflow
1 2 3 4 5 6 7 8 9 10
| #!/bin/bash
trap "kill 0" EXIT while true; do if inotifywait -qq -e close_write docs/diagrams/; then echo "→ re-render" plantuml -tsvg -o public/img/diagrams/ docs/diagrams/*.puml fi done
|
启这个脚本 + 浏览器 localStorage: refreshInterval: 5 ——「边写边看图」全流程。
8. 预处理:自动注入皮肤
CI 渲染时想统一加皮肤,但不想改每个 .puml 文件:
1 2 3 4 5 6 7 8 9 10 11
| for puml in docs/diagrams/*.puml; do awk '/^@startuml/ { print print "skinparam defaultFontName \"Noto Sans CJK SC\"" next } { print } ' "$puml" > /tmp/processed.puml plantuml -tsvg /tmp/processed.puml -o rendered/ done
|
用 sed 简易版
1 2
| sed '/^@startuml/a skinparam defaultFontName "Noto Sans CJK SC"' file.puml > /tmp/processed.puml plantuml -tsvg /tmp/processed.puml
|
9. 错误处理 / 日志
默认输出
1 2
| plantuml -tsvg diagram.puml
|
静默
1
| plantuml -tsvg -quiet diagram.puml
|
或者 -SINGLE_LINE_LOG=quiet。CI 用 2>/dev/null。
详细日志
1
| plantuml -tsvg -DEBUG diagram.puml 2> debug.log
|
调试 .h 文件 / 字体加载问题时用。
10. 标准库路径
你的 puml 可以用 !include <C4/Container> 之类引用标准库图(C4 模型、BPMN、Archimate 等)。
自定义 stdlib
1
| plantuml -stdlib %your-custom-stdlib-path%
|
11. 用 plantuml 跑 stdin + 拿 stdout
1 2
| echo 'Alice -> Bob' | plantuml -pipe -tsvg
|
但 PlantUML 输出含 XML 头——直接 cat:
1 2 3
| svg="$(echo 'Alice -> Bob' | plantuml -pipe -tsvg)"
echo "<div>$svg</div>" > /tmp/page.html
|
多文件打包
1 2 3
| for puml in files/*.puml; do echo "<div>$(plantuml -pipe -tsvg < "$puml")</div>" done > all.html
|
12. 注入 Python / JS 预处理
如果你想让 plantuml 在 render 前自动 lint、加指纹、做兼容处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #!/bin/bash
preprocess() { python3 -c " import sys src = sys.stdin.read() # 加全局皮肤 src = src.replace('@startuml', '@startuml\n!theme cyborg', 1) # 移除注释 src = '\n'.join(l for l in src.split('\n') if not l.strip().startswith(\"' ''\")) sys.stdout.write(src) " }
cat docs/diagrams/system.puml | preprocess | plantuml -pipe -tsvg > out.svg
|
1 2 3
| plantuml -tsvg diagram.puml
npx svgo -i rendered/diagram.svg -o rendered/diagram.min.svg
|
或者注入企业颜色:
1 2 3
| plantuml -tsvg diagram.puml sed -i 's|fill="#FFFFFF"|fill="#FAF9F6"|g' rendered/diagram.svg sed -i 's|font-family="sans-serif"|font-family="Inter"|g' rendered/diagram.svg
|
14. 完整 CI pipeline 例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| name: Render PlantUML diagrams on: push: paths: ['docs/diagrams/**']
jobs: render: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install PlantUML run: | sudo apt-get update sudo apt-get install -y fonts-noto-cjk wget -O plantuml.jar https://github.com/plantuml/plantuml/releases/download/v1.2026.x/plantuml-1.2026.x.jar - name: Lint run: | for f in docs/diagrams/*.puml; do java -jar plantuml.jar -checkonly "$f" || exit 1 done - name: Render run: | java -jar plantuml.jar -tsvg -o public/img/diagrams/ docs/diagrams/*.puml - name: Diff run: | git diff --exit-code public/img/diagrams/ || { echo "图有改动但 puml 没动,PR 必检" exit 1 } - name: Commit run: | git add public/img/diagrams/ git commit -m "docs: re-render diagrams" git push
|
关键:git diff --exit-code 让图过时变成 build failure。
15. 一段「综合」脚本(覆盖 80% 用例)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| #!/bin/bash
set -e
INPUT_DIR="${1:-docs/diagrams}" OUTPUT_DIR="${2:-public/img/diagrams}" mkdir -p "$OUTPUT_DIR"
if ! command -v plantuml > /dev/null; then echo "❌ plantuml not found" exit 1 fi
echo "→ 校验 puml" fail=0 while read -r puml; do if ! plantuml -checkonly "$puml" 2>&1 | grep -qE "ERROR"; then : else echo "❌ $puml" fail=1 fi done < <(find "$INPUT_DIR" -name '*.puml' -type f) [ "$fail" -eq 0 ] || exit 1
echo "→ 渲染" plantuml -tsvg -thread 4 -o "$OUTPUT_DIR" "$(find "$INPUT_DIR" -name '*.puml')"
for svg in "$OUTPUT_DIR"/*.svg; do [ -f "$svg" ] || continue npx svgo -i "$svg" -o "$svg" 2>/dev/null || true done
echo "✓ done"
|
16. 调试 PlantUML CLI 自身
1 2 3 4 5 6 7 8 9
| plantuml -version java -version
plantuml -checkonly -DEBUG diagram.puml 2>&1 | grep -i font
plantuml -tsvg -DEBUG -J-Djdk.trace=true diagram.puml 2>&1 | head -50
|
排除具体错误
| 错误 |
怎么排查 |
Could not find Graphviz |
装 graphviz,或换 ELK |
Java not found |
apt install default-jdk |
font not found |
fc-list 看字体;用 -fontpath 指定 |
diagram not supported |
改用 client render / 换 cheat |
OutOfMemoryError: Java heap space |
加 -Xmx2048m JAVA_OPTS |
小结
- plantuml CLI 不是
单文件 1 命令——管道、监控、并发、增量都有方案
- 增量是提升 CI 效率的关键—— 8 张图 vs 200 张图差 50×
- 调试时
plantuml -checkonly -DEBUG 是入口
- 配合
inotifywait + fswatch 边写边看
下一步