Skip to content

feat(export): bundle session caches into html-wasm --execute output#9897

Merged
dmadisetti merged 1 commit into
mainfrom
dm/wasm-cache-export
Jul 9, 2026
Merged

feat(export): bundle session caches into html-wasm --execute output#9897
dmadisetti merged 1 commit into
mainfrom
dm/wasm-cache-export

Conversation

@dmadisetti

@dmadisetti dmadisetti commented Jun 15, 2026

Copy link
Copy Markdown
Member

📝 Summary

Expands marimo export html-wasm --execute to leverage [tools.marimo.runtime] cache_cells = true.
This flag is set on export, cell execution caching is enabled, and all cell content moved over to the public http store. The Dual store actives when in WASM and cache is served over http.

Screen.Recording.2026-07-08.at.4.39.03.PM.mov

closes #9327

@vercel

vercel Bot commented Jun 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
marimo-docs Ready Ready Preview, Comment Jul 8, 2026 11:27pm

Request Review

@mscolnick

Copy link
Copy Markdown
Contributor

Is this ready for review? Anything blocking moving it out of draft?

@dmadisetti
dmadisetti force-pushed the dm/wasm-cache-export branch from d5cbda8 to 1a311e2 Compare June 29, 2026 17:58
@dmadisetti
dmadisetti force-pushed the dm/wasm-cache-export branch from 1a311e2 to e8cdc61 Compare June 30, 2026 18:27
Base automatically changed from dm/lazy-store-merge to main June 30, 2026 19:20
@dmadisetti
dmadisetti force-pushed the dm/wasm-cache-export branch from e8cdc61 to e79334e Compare June 30, 2026 19:25
@dmadisetti
dmadisetti force-pushed the dm/wasm-cache-export branch from e79334e to dfd4acf Compare July 1, 2026 21:16
@dmadisetti
dmadisetti force-pushed the dm/wasm-cache-export branch from cd9695e to 1716f32 Compare July 2, 2026 22:46
@dmadisetti
dmadisetti force-pushed the dm/wasm-cache-export branch from 96dcc10 to f67a52f Compare July 2, 2026 23:04
@dmadisetti
dmadisetti force-pushed the dm/wasm-cache-export branch from f67a52f to 89c55f1 Compare July 6, 2026 17:30
@dmadisetti
dmadisetti force-pushed the dm/wasm-cache-export branch from 89c55f1 to 1ad86c1 Compare July 6, 2026 17:42
@dmadisetti
dmadisetti force-pushed the dm/wasm-cache-export branch from de03fc5 to de482e1 Compare July 8, 2026 19:43
@dmadisetti
dmadisetti changed the base branch from main to dm/cache-robustness July 8, 2026 19:44
@dmadisetti
dmadisetti force-pushed the dm/cache-robustness branch from 32b44cb to 72f09a2 Compare July 8, 2026 20:27
@dmadisetti
dmadisetti force-pushed the dm/wasm-cache-export branch from de482e1 to 9a0e277 Compare July 8, 2026 20:31
Base automatically changed from dm/cache-robustness to main July 8, 2026 23:08
@dmadisetti
dmadisetti force-pushed the dm/wasm-cache-export branch from 9a0e277 to 862ed09 Compare July 8, 2026 23:26
@dmadisetti dmadisetti added the includes-media Description includes multimedia provided to illustrate functionality. label Jul 8, 2026
@dmadisetti
dmadisetti marked this pull request as ready for review July 8, 2026 23:44
Copilot AI review requested due to automatic review settings July 8, 2026 23:44
@dmadisetti
dmadisetti requested review from mscolnick and peter-gy July 8, 2026 23:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for bundling execution-time cell caches into marimo export html-wasm --execute output so exported WASM notebooks can reuse precomputed results (via public/cache/) instead of recomputing in-browser.

Changes:

  • Introduces per-notebook cache export manifests (written on kernel teardown when caching is enabled) and a bundling step that copies manifest-listed blobs into <out_dir>/public/cache/.
  • Extends the export execution path to optionally enable cache export behavior and to trigger bundling after the kernel completes.
  • Adds focused unit tests for manifest naming/dumping and for cache bundling behavior (including traversal rejection).

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/_server/export/test_exporter.py Adds a note clarifying where cache-export coverage lives.
tests/_save/loaders/test_cache_export.py New unit tests for manifest naming, manifest dumping, and cache-export teardown gating.
tests/_cli/test_export_cache_bundle.py New unit tests for bundling cache blobs into public/cache/ and safety behaviors.
marimo/_session/managers/kernel.py Requests clean kernel shutdown and adds a bounded join to allow cache flush before kill.
marimo/_server/export/init.py Implements manifest-based cache bundling and wires it into html-wasm --execute execution flow.
marimo/_save/stores/file.py Adds export_manifest_name() helper for deriving the manifest filename.
marimo/_save/loaders/lazy.py Adds manifest dumping and a merged export_keys() for bundling.
marimo/_save/loaders/init.py Re-exports dump_cache_manifests.
marimo/_runtime/runtime.py Wires CacheCallbacks to read cache_cells from config at teardown time.
marimo/_runtime/callbacks/cache.py Adds cache_cells_enabled() and writes export manifests on teardown when enabled.
marimo/_runtime/callbacks/init.py Exposes cache_cells_enabled.
marimo/_cli/export/commands.py Passes cache_export_dir for html-wasm --execute runs and documents bundling behavior.

Comment on lines +394 to +413
try:
keys: list[str] = json.loads(manifest_file.read_text())
except (OSError, ValueError) as e:
LOGGER.warning("Failed to read cache export manifest: %s", e)
return

cache_dst = out_dir / "public" / "cache"
copied = 0
for key in keys:
# A stale/tampered manifest key could otherwise escape the cache dir.
rel = PurePosixPath(key)
if not isinstance(key, str) or rel.is_absolute() or ".." in rel.parts:
LOGGER.warning("Skipping unsafe cache manifest key: %r", key)
continue
src_file = cache_src / key
if src_file.exists():
dst_file = cache_dst / key
dst_file.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(src_file, dst_file)
copied += 1
Comment thread marimo/_server/export/__init__.py Outdated
Comment on lines +455 to +472
@@ -392,11 +456,20 @@
resolved = config.get_config()
display_config = resolved["display"]

if cache_export_dir is not None:
# NB. drop a prior run's manifest so we never bundle a stale key set.
_cache_export_manifest_path(path).unlink(missing_ok=True)

session_view, did_error = await run_app_until_completion(
file_manager,
cli_args,
argv=argv,
cache_export=cache_export_dir is not None,
)
if cache_export_dir is not None:
# NB. the run joined the kernel, which wrote the manifest on shutdown,
# so it's on disk to read now.
bundle_cache_export(path, cache_export_dir)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good distinction. Making this more opt in

Comment on lines +11 to +22
def export_manifest_name(notebook_filename: str | None) -> str:
"""Filename of the export manifest for a notebook, derived from its path.

Per-notebook (not a shared name) so notebooks sharing a cache dir, or
concurrent exports, don't clobber each other. Kernel and exporter derive it
identically. A dotfile so it can't collide with a cache key.
"""
import re

stem = Path(notebook_filename).stem if notebook_filename else "notebook"
slug = re.sub(r"[^0-9A-Za-z._-]+", "-", stem).strip("-") or "notebook"
return f".{slug}-export.json"
Bundle a session's per-cell and per-function caches into the output of
marimo export html-wasm --execute, so a dependency-free browser (Pyodide)
can skip recomputation. Stacked on the cache-robustness PR (#10109), which
provides the graceful-degrade / hashing-parity restore machinery this relies
on to consume the bundled caches without the original deps.

This pull request was authored by a coding agent.
@dmadisetti
dmadisetti force-pushed the dm/wasm-cache-export branch from 862ed09 to 1bb2d02 Compare July 9, 2026 00:21
@dmadisetti
dmadisetti merged commit 503b7f4 into main Jul 9, 2026
45 of 47 checks passed
@dmadisetti
dmadisetti deleted the dm/wasm-cache-export branch July 9, 2026 16:15
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

🚀 Development release published. You may be able to view the changes at https://marimo.app?v=0.23.14-dev46

mscolnick added a commit that referenced this pull request Jul 9, 2026
…oop (#10124)

The cache-export change (#9897) added a blocking join(timeout=5) to
close_kernel to let the kernel flush pending work. But close_kernel runs
synchronously on the event loop when the live edit server closes a
session (restart_session, websocket disconnect), so the wait stalled the
server for up to 5s. This broke the playwright suite: the toggle-cell
test's kernel restart froze the server past the 5000ms click timeout and
triggered 'Invalid session id' races.

Make the graceful stop-and-join opt-in (graceful=False by default); only
the export path (run_app_until_completion) enables it, where blocking is
fine and the flushed cache manifest is needed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request includes-media Description includes multimedia provided to illustrate functionality.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cross-environment static cache hosting for WASM (i.e. read mo.persistent_cache output in Pyodide)

4 participants