Wait for excalidraw to finish rendering before copying the html - #750
Open
rettier-claudi wants to merge 1 commit into
Open
Wait for excalidraw to finish rendering before copying the html#750rettier-claudi wants to merge 1 commit into
rettier-claudi wants to merge 1 commit into
Conversation
Drawings embedded into a note (![[Drawing.excalidraw]]) are rendered by an async markdown post processor of the excalidraw plugin, which replaces the `.internal-embed` element obsidian created with the drawing once it is done. Obsidian does not wait for post processors before it reports a page as rendered, and the excalidraw plugin additionally queues that work in a global task queue with a concurrency limit, so on pages with several or large drawings the export copied the html while the placeholder embeds were still in it. The drawings were then missing from the exported page and only the bare embed element was left behind, seemingly at random. renderMarkdownView now waits for those embeds to be resolved before it copies the preview element. Inserting the drawings grows the document, which can make obsidian unload the sections that are now outside of the viewport, so the existing section check is repeated afterwards and the fallback renderer is used if sections went missing. renderMarkdownViewFallback waits per section. renderExcalidraw had the same race when a drawing is exported as its own page: it slept a fixed 500ms and then read `view.excalidrawData.scene`, which throws or yields an empty drawing when the view has not finished loading. It now waits for the view to report the scene as loaded and fails with a proper message instead of a TypeError. Verified with the docker export harness on a vault of 8 embedded drawings: before the change 0-2 of 8 drawings were exported over three runs, after it 8 of 8 in each run, with the page otherwise unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Disclosure
This patch was written by an AI agent (Claude Code), driven and reviewed by me. I am disclosing that up front so you can weigh the diff accordingly. The bug itself is real and hit me in my own vault, and the fix is verified against a reproduction rather than reasoned about in the abstract — details below. Happy to rework anything you'd rather see solved differently.
The bug
Drawings embedded into a note (
![[Drawing.excalidraw]]) are rendered by an async markdown post processor of the excalidraw plugin, which replaces the.internal-embedelement obsidian created with the drawing once it is done. That work is additionally queued in the excalidraw plugin's global task queue with a concurrency limit (3 by default).Obsidian does not wait for post processors before it reports a page as rendered, and
renderMarkdownViewonly waits for sections, transclusions andblock-language-*blocks — nothing that covers excalidraw. SonewSizerEl.innerHTML = sizerEl.innerHTMLcan snapshot the page while the placeholder embeds are still in it. The drawing is then missing from the exported page and a bare<span class="internal-embed ...">is left in its place. With one or two small drawings the post processor usually wins the race, with several or large ones it does not, which is why this looks random.renderExcalidrawhad the same problem when a drawing is exported as its own page: it slept a fixed500msand then readview.excalidrawData.scene, which throws aTypeErroror yields an empty drawing when the view has not finished loading yet.The change
renderMarkdownViewwaits for pending excalidraw embeds before copying the preview element. An embed counts as pending while it is still an.internal-embedwhosesrcresolves to a file the excalidraw plugin claims viaisExcalidrawFile, and which contains none of excalidraw's own markers. Block and section references are excluded because excalidraw embeds those as text, so they would never resolve. The wait is bounded (3s without progress, 30s hard cap) and logs a warning naming the embeds it gave up on.renderMarkdownViewFallbackwaits per section.renderExcalidrawwaits for the view to report its scene as loaded instead of sleeping a fixed amount, and returns a properfailRendermessage instead of throwing. The view flags are only checked when the installed excalidraw version actually exposes them, so older versions still work.Everything is a no-op when the excalidraw plugin is not enabled, and the wait returns immediately when a page has no pending excalidraw embeds.
Verification
Using this repo's docker export harness (real obsidian under Xvfb) on a vault with 8 large drawings embedded into one note, three runs per variant:
<span class="internal-embed">The standalone drawing pages are unchanged in both variants, and lighter vaults (4 and 2 embedded drawings) export identically before and after, so the fast path is not affected.
Known limitation, not addressed here
This only helps in excalidraw's Native SVG embed mode. In PNG / SVG-image mode excalidraw produces
blob:URLs whichinlineMediacannot resolve — that is the separate limitationvalidateSettingsalready warns about, and I left it alone.