我使用Excalidraw管理我的博客图表。
I use excalidraw to manage my diagrams for my blog

原始链接: https://blog.lysk.tech/excalidraw-frame-export/

我大量使用 Excalidraw 进行头脑风暴、解释概念,现在还用于博客写作。在撰写第一篇文章时,我发现不断地重新导出图表——每次更改都需要耗时 45 秒——严重打断了我的工作流程。为了解决这个问题,我最初创建了一个 GitHub Action,它可以自动将更改的 Excalidraw 文件中的框架元素(名称带有“export_”前缀)导出为明亮和黑暗模式的 SVG。 然而,这个解决方案需要推送到 GitHub 才能进行本地预览,造成了令人沮丧的延迟。然后,我开发了一个 Excalidraw 的 VSCode 扩展,每当 Excalidraw 文件保存时,它都会*自动*将框架元素导出为 SVG。这提供了实时的本地预览,显著改善了写作体验。 该扩展将导出的文件命名为 `${image_name}.light.exp.svg` 和 `${image_name}.dark.exp.svg`,使其易于引用。我已经将该扩展发布到我的 GitHub 分支,希望它能激发对核心 Excalidraw 扩展的改进。

Hacker News 新闻 | 过去 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 我使用 excalidraw 来管理我的博客 (lysk.tech) 的图表。 14 分,作者 mlysk,42 分钟前 | 隐藏 | 过去 | 收藏 | 3 条评论 帮助 gethly 1 分钟前 | 下一个 [–] 我也是。我开始把它用于 Gethly 博客。它并不完美,有些事情让我抓狂,但总的来说,它比我以前使用的 draw.io 更好。Excalidraw 也有一些很棒的风格,感觉很对劲 :) 回复 emil-lp 11 分钟前 | 上一个 [–] 应该归类为 Show HN。现在读起来像是一个我从未听说过的程序的扩展的广告。 emil-lp 8 分钟前 | 父评论 [–] 显然 Excalidraw 是一个开源的虚拟手绘风格白板。协作且端到端加密。 https://github.com/excalidraw/excalidraw 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系方式 搜索:
相关文章

原文

TL;DR I use an Excalidraw, wrap the elements of interest with a frame, name it with export_ prefix, my forked excalidraw extension automatically generates SVGs for light and dark mode.

export export

Using Excalidraw

I used Excalidraw a lot in the past.

  1. When breaking down a technical problem for myself
  2. When explaining a concept or an architecture to my coworkers.

Just recently a new usecase evolved.

  1. Expressing my thoughts in my Blog.

While writing my first article the dependency between graphics and the text lead to a lot frustration. Fine-tuning the graphic led to an easier text. Changes in the text made me realize that some information in the graphic is not needed to grasp what should land.

The Problem

Every change in a graphic in Excalidraw meant 9 clicks in Excalidraw.

  1. Selecting the frame
  2. pressing export
  3. choose the right name + darkmode/lightmode postfix
  4. export
  5. switch light/dark mode
  6. choose the right name + darkmode/lightmode postfix
  7. export again
  8. realize that one label crossed the frame boundary
  9. starting at 1 again.

It took me about 45 seconds.

Automate it :-) .

FS events - client side write

First approach - the GitHub action

...20 minutes later... A bit of bash thanks to open source (specifically JonRC's excalirender) - it worked...

A little GitHub action that:

  1. looks for changed excalidraw files in the last push,
  2. uses jq to find frames inside of those,
  3. exports them in dark and light mode as [framename]-[light/dark],
  4. commits those new svg files to the repo again.
See code here:
name: Export Excalidraw Frames

on:
push:
branches:
- main
pull_request:
branches:
- main

permissions:
contents: write

jobs:
export-frames:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 2

- name: Get changed Excalidraw files
id: changed-files
run: |

if [[ "${{ github.event_name }}" == "push" ]]; then
CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD | grep '\.excalidraw$' || true)
else

CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }} HEAD | grep '\.excalidraw$' || true)
fi

if [ -z "$CHANGED_FILES" ]; then
echo "No changed .excalidraw files found"
echo "has_changes=false" >> $GITHUB_OUTPUT
else
echo "Changed files:"
echo "$CHANGED_FILES"
echo "$CHANGED_FILES" > /tmp/changed_files.txt
echo "has_changes=true" >> $GITHUB_OUTPUT
fi

- name: Install excalirender
if: steps.changed-files.outputs.has_changes == 'true'
run: |
curl -fsSL https://raw.githubusercontent.com/JonRC/excalirender/main/install.sh | sh
echo "$HOME/.local/bin" >> $GITHUB_PATH
excalirender --version || echo "excalirender installed"

- name: Export frames for changed files
if: steps.changed-files.outputs.has_changes == 'true'
run: |

cat > /tmp/export_frames.sh << 'EOF'


EXCALIDRAW_FILE="$1"
OUTPUT_DIR="$(dirname "$EXCALIDRAW_FILE")"


FRAME_NAMES=$(jq -r '.elements[] | select(.type == "frame") | .name // "frame-" + .id' "$EXCALIDRAW_FILE")

if [ -z "$FRAME_NAMES" ]; then
echo "No frames found in $EXCALIDRAW_FILE"
exit 0
fi

echo "Exporting frames from $EXCALIDRAW_FILE"


while IFS= read -r frame_name; do
if [ -n "$frame_name" ]; then
echo " Exporting frame: $frame_name"


safe_name=$(echo "$frame_name" | sed 's/[<>:"/\\|?*]/-/g' | sed 's/\s+/-/g')


excalirender "$EXCALIDRAW_FILE" --frame "$frame_name" -o "${OUTPUT_DIR}/${safe_name}-light.svg"


excalirender "$EXCALIDRAW_FILE" --frame "$frame_name" --dark -o "${OUTPUT_DIR}/${safe_name}-dark.svg"
fi
done <<< "$FRAME_NAMES"

echo " ✓ Exported all frames from $EXCALIDRAW_FILE"
EOF

chmod +x /tmp/export_frames.sh


while IFS= read -r file; do
if [ -n "$file" ]; then
echo "Processing: $file"
/tmp/export_frames.sh "$file"
fi
done < /tmp/changed_files.txt

- name: Commit exported SVGs
if: steps.changed-files.outputs.has_changes == 'true'
run: |
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"


git add **/*.svg 2>/dev/null || git add *.svg 2>/dev/null || true


if git diff --staged --quiet; then
echo "No new SVG files to commit"
else
echo "Committing exported SVG files"
git commit -m "chore: export Excalidraw frames as SVGs

- Exported frames from changed .excalidraw files
- Generated light and dark mode variants

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>"
git push
fi

Awesome! Enough to continued working on my article.

Problems with approach 1

After working with this approach for some time I faced various issues.

  1. The library I used had some rendering bugs (same as this one)
  2. The process involved spinning up an x86 based docker image I couldn't get running on my ARM-based Mac

I circumvented 1.) with additional labels added but 2.) broke the whole concept. Not being able to run the export locally meant I needed to push the Excalidraw file to GitHub, wait for the pipeline to finish, and pull the new commit before I could see new images or changes in images reflected.

So the solution kind of worked but reviewing the blog post locally was only possible with outdated images.

A new Idea: Add auto-export to Excalidraw

What if Excalidraw's VSCode extension would check the open *.excalidraw file for changes and automatically export each frame as two separate SVG files - one in dark mode, one in light mode?

I took some time with Claude over the weekend to YOLO code. The result:

If I edit my Excalidraw in VSCode, all I need to do to make a section available for my blog post:

  1. wrap the elements with a frame
  2. name the frame like export_${image_name}

The extension will pick up the frame, export it as SVG in dark and light mode, and save two SVGs named ${image_name}.light.exp.svg and ${image_name}.dark.exp.svg next to the Excalidraw file.

Live preview locally

Now that those images are available locally and update whenever I change a frame in my Excalidraw, I can reference them via auto-complete and preview in the editor, see them rendered in the Preview tab.

export export

I am pretty happy with the result. I spent only a couple of hours including this writeup. Using the tool brings joy since it solves a real pain.

I can't wait to use it extensively in the articles in the making - SQLite on Git.

One thing I'm not sure about, though. After talking to others about this approach I could see my approach bringing value to the original Excalidraw extension itself. But I wouldn't create a pull request - since I don't own the code - or rather, I don't want to take ownership. I'm thinking to open an issue, describe the problem and the solution to serve as inspiration instead.

If others find this useful and play around with it - I created artifacts for the release section in my GitHub fork that allows others to download and use my extension. For now, that's enough!

联系我们 contact @ memedata.com