0013. 그림 도구로 Excalidraw를 들이고 옵시디언 형식의 파일로 둔다
- 상태: 채택
- 날짜: 2026-09-29
- 관련: src/shared/excalidrawFile.ts, src/renderer/src/workspace/DrawingEditor.tsx, src/renderer/src/workspace/drawings.ts, src/renderer/src/workspace/excalidrawAssets.ts
작업 문서 옆에 그림을 두고 앱 안에서 바로 그리고 고치려 한다. 같은 그림을 옵시디언에서도 열 수 있어야 한다. 옵시디언의 Excalidraw 플러그인은 그림을 .excalidraw.md 마크다운 파일 안의 코드 블록으로 둔다.
앱은 Electron이고 인터넷이 없을 때도 쓴다. Excalidraw는 캔버스 글꼴을 기본으로 외부 CDN(esm.sh)에서 받고, 내장 저장은 브라우저 파일 API(browser-fs-access)를 써서 Electron에서 실패한다는 보고가 있다(excalidraw/excalidraw#6750).
@excalidraw/excalidraw를 들여 그림 탭의 편집기로 쓴다. 편집기 모듈은React.lazy로 그림 탭을 처음 열 때 불러온다.- 파일은 옵시디언 Excalidraw 플러그인과 호환되는
.excalidraw.md로 둔다. 읽을 때는json과compressed-json을 모두 받고, 쓸 때는 그림 데이터를 압축하지 않은json으로 쓴다. - 글꼴은 앱에 넣고 절대 URL 에셋 경로로 불러온다. postinstall이 패키지의 글꼴을
src/renderer/public/excalidraw/fonts/로 복사하고,window.EXCALIDRAW_ASSET_PATH에 페이지 주소로 만든 절대 URL을 넣는다. 외부 CDN을 쓰지 않는다. - 저장은 앱이 맡는다. 편집기 설정의 자동 저장과 상관없이 마지막 변경 1초 뒤 저장하고,
Mod+S는 곧바로 저장한다. 내장 메뉴의 열기, 저장, 내보내기, 이미지로 저장, 테마 바꾸기는 숨긴다. - 이미지 넣기는 뺀다. 이미지 도구를 숨기고, 파일이 든 붙여넣기와 끌어다 놓기를 막는다.
근거 / 검토한 대안
섹션 제목: “근거 / 검토한 대안”- tldraw를 쓴다. 편집기로는 쓸 만하지만 파일 형식이 옵시디언 Excalidraw 플러그인과 호환되지 않아, 같은 그림을 옵시디언에서 열 수 없다.
compressed-json으로 쓴다. 플러그인의 기본 형식이라 파일이 작다. 그러나 base64로 압축된 한 덩어리라 git diff로 무엇이 바뀌었는지 읽을 수 없다. 플러그인은json도 읽으므로 호환은 잃지 않는다.- 글꼴을 CDN에서 받는다. 설치 파일은 작아지지만 오프라인에서 손글씨 글꼴이 깨진다. 에셋 경로를 상대 경로로 주면
file://로 띄운 빌드에서Invalid URL이 나서(excalidraw/excalidraw#8870) 절대 URL을 쓴다. - 내장 저장을 쓴다. Electron에서 실패한다는 보고가 있고, 탭의 미저장 표시와 닫기 확인 창(PR #51)에 이을 수 없다.
- 채택안: 옵시디언과 파일을 주고받을 수 있고, git diff로 그림 데이터를 읽을 수 있고, 오프라인에서도 글꼴이 보인다. 저장을 앱이 맡으니 다른 파일 탭과 같은 미저장 표시와 닫기 흐름을 쓴다.
- 설치 파일이 약 16MB 커진다(JS 약 2.8MB, 글꼴 약 13MB). 편집기는 lazy로 불러와 그림 탭을 열지 않으면 앱 시작에는 영향이 없다.
- React 19와 함께 설치하면 하위 의존성
@radix-ui/react-tabs1.0.2의 peer 경고가 난다(excalidraw/excalidraw#11500). 동작 문제는 보고되지 않아 그대로 둔다. - 옵시디언 플러그인이 만든
compressed-json파일을 이 앱에서 저장하면json으로 바뀐다. - 이미지가 든 그림은 이 앱에서 이미지를 보여 주지 않는다. 이미지 넣기가 필요해지면 따로 결정한다.