feat(wasm): render notebook snapshot while Pyodide initializes#9502
Merged
Conversation
Previously the WASM loader blocked the entire app behind a spinner until Pyodide finished downloading. With the new snapshot embedded by `marimo export html-wasm --execute`, render cells (code + cached outputs) on first paint and let Pyodide download in the background. - Gate spinner on whether cells exist, not whether Pyodide is pending - Toast Pyodide init failures instead of throwing when a snapshot is shown - Add a footer "Pyodide" indicator that mirrors the "Kernel" one
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
There was a problem hiding this comment.
No issues found across 7 files
Architecture diagram
sequenceDiagram
participant UI as React UI
participant Footer as Footer Component
participant PyStatus as PyodideStatus (NEW)
participant PyApp as RunApp (CHANGED)
participant PyLoader as PyodideLoader (CHANGED)
participant Cells as Cells Store
participant Bridge as PyodideBridge
participant Pyodide as Pyodide Runtime
Note over UI,Pyodide: Start-up Sequence (snapshot path)
UI->>PyApp: Render notebook
alt Snapshot with cells present
PyApp->>Cells: hasCellsAtom
Cells-->>PyApp: true
Note over PyApp: Skip spinner gate — show cells immediately
PyApp->>UI: Paint cells (code + cached outputs)
else No cells yet
PyApp->>Cells: hasCellsAtom
Cells-->>PyApp: false
PyApp->>UI: Show spinner (original behavior)
end
Note over UI,Pyodide: Background Pyodide Initialization
UI->>PyLoader: Mount (parallel with cell render)
PyLoader->>Cells: hasCellsAtom
PyLoader->>Cells: hasAnyOutputAtom
PyLoader-->>PyLoader: shouldShowSpinner(hasCells, hasOutput, mode, codeHidden)
alt shouldShowSpinner = true (nothing visible)
PyLoader->>UI: Show WasmSpinner (full-screen)
else hasCells and (code visible or has output)
PyLoader->>UI: Render children (snapshot stays visible)
end
PyLoader->>Bridge: Wait for initialized.promise
Bridge->>Pyodide: Initialize (download + boot)
alt Pyodide ready
Bridge->>Bridge: set wasmInitStatusAtom = "ready"
Bridge-->>PyLoader: Promise resolves
PyLoader->>PyLoader: No longer pending
else Pyodide fails
Bridge->>Bridge: set wasmInitStatusAtom = "error"
Bridge-->>PyLoader: Promise rejects
alt Snapshot is showing (nothingToShow = false)
PyLoader->>UI: toast("Failed to start notebook runtime")
Note over PyLoader: Error is surfaced as toast, snapshot remains visible
else No snapshot (nothingToShow = true)
PyLoader->>UI: throw error (caught by error boundary)
end
end
Note over UI,Pyodide: Footer Indicator (NEW)
Footer->>PyStatus: Render component
PyStatus->>PyStatus: Check isWasm() and wasmInitStatusAtom
alt Status = "ready" or not WASM
PyStatus->>PyStatus: Return null (hidden)
else Status = "loading"
PyStatus->>UI: Show spinner + "Pyodide" label
else Status = "error"
PyStatus->>UI: Show error icon + "Pyodide" label
PyStatus->>PyStatus: Tooltip: "Pyodide failed to initialize"
end
Note over Footer: Mirrors Kernel status indicator behavior
Contributor
There was a problem hiding this comment.
Pull request overview
Enables WASM (Pyodide) notebooks exported with an embedded snapshot to render immediately (cells + cached outputs) while Pyodide continues initializing in the background, instead of blocking the entire UI behind a loader.
Changes:
- Update the WASM loader gating logic to show a spinner only when there’s nothing meaningful to render yet (no hydrated cells, or headless run mode with no outputs).
- Surface Pyodide init failures via a toast (when snapshot content is already visible) and add a footer “Pyodide” status indicator.
- Skip the “Connecting…” gate in run mode when cells already exist (e.g., from an embedded snapshot).
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| frontend/src/core/wasm/state.ts | Adds a wasmInitStatusAtom to track Pyodide init state. |
| frontend/src/core/wasm/PyodideLoader.tsx | Stops blocking render on Pyodide init; introduces shouldShowSpinner predicate and error-toasting behavior. |
| frontend/src/core/wasm/bridge.ts | Updates WASM bridge to set init status to ready/error based on worker messages. |
| frontend/src/core/wasm/tests/PyodideLoader.test.ts | Adds unit tests for the spinner gating predicate. |
| frontend/src/core/run-app.tsx | Avoids showing the connecting spinner when cells already exist. |
| frontend/src/components/editor/chrome/wrapper/footer.tsx | Adds the Pyodide status indicator to the footer. |
| frontend/src/components/editor/chrome/wrapper/footer-items/pyodide-status.tsx | Implements the footer Pyodide init indicator and tooltip. |
Comment on lines
128
to
140
| this.rpc.addMessageListener("initializedError", ({ error }) => { | ||
| // If already resolved, show a toast | ||
| if (this.initialized.status === "resolved") { | ||
| Logger.error(error); | ||
| toast({ | ||
| title: "Error initializing", | ||
| description: error, | ||
| variant: "danger", | ||
| }); | ||
| } | ||
| store.set(wasmInitStatusAtom, "error"); | ||
| this.initialized.reject(new Error(error)); | ||
| }); |
If `initializedError` fires after Pyodide has already resolved, return early instead of corrupting the Deferred status and flipping the footer "Pyodide" indicator to error. The worker is healthy; the toast already surfaces the runtime error.
|
🚀 Development release published. You may be able to view the changes at https://marimo.app?v=0.23.6-dev32 |
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.
Previously the WASM loader blocked the entire app behind a spinner until
Pyodide finished downloading. With the new snapshot embedded by
marimo export html-wasm --execute, render cells (code + cached outputs)on first paint and let Pyodide download in the background.