feat: kernel-aware ES module support for ipyvue - #1169
Merged
Conversation
maartenbreddels
force-pushed
the
feat/ipyvue-esm-modules
branch
from
July 4, 2026 14:04
aaba0b0 to
467fb56
Compare
maartenbreddels
force-pushed
the
feat/ipyvue-esm-modules
branch
from
July 4, 2026 14:18
467fb56 to
48474bf
Compare
maartenbreddels
temporarily deployed
to
feat/ipyvue-esm-modules - solara-stable PR #1169
July 4, 2026 19:54 — with
Render
Destroyed
maartenbreddels
added a commit
to widgetti/ipyreact
that referenced
this pull request
Jul 4, 2026
define_module(name, "/static/bundle.mjs") imports the module from the url instead of shipping the code over the widget model (e.g. a bundle served from the app's static dir, cacheable and preloadable). A plain str now always means a url; inline source moves to the explicit code keyword. Note: under solara server define_module is patched by solara.server.esm, which needs the matching update (widgetti/solara#1169) for the new signature to apply there. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ipyvue's vue3 branch gains define_module for precompiled ESM bundles (vite-built .vue components); this provides the same server-side handling ipyreact modules get in esm.py: definitions recorded once, Module widgets materialized per kernel (recreated when context.restart closed them, so in-place reload works), bundle Paths watched by the reloader, per-kernel bookkeeping dropped on kernel close. No-op for ipyvue without ES module support (hasattr-gated); the unit tests skip likewise until an ipyvue release ships it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
define_module accepts a url (e.g. a bundle served from the app's static dir); the page emits <link rel="modulepreload"> for url-backed modules, so the browser fetches them in parallel with kernel startup instead of waiting for the Module widget to arrive over the websocket (es-module-shims honors modulepreload hints in shim mode). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ource A plain str was ambiguously code-or-url based on a prefix heuristic; now str always means a url, Path means a file, and inline source moves to an explicit code keyword. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
versioned_url appends ?v=<content-hash> to module urls that solara serves itself (/static/public/...); the SAME url is used for the modulepreload hint in the page and the Module widget, so the preload is always a cache hit. StaticPublic sends max-age=1y, immutable when the requested hash matches the current file content - any rebuild changes the url, so caching can be aggressive without staleness. Urls with an existing query string and external urls pass through untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…serving ipyreact modules get the same treatment as ipyvue ones: define_module accepts a url (str = url, code= for inline source), the widget gets the content-hash-versioned url, and the page preloads it. versioned_url moves to server.py so esm.py does not pull in ipyvue. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Exactly one of module (a Path), code= or url= must be passed, matching the ipyvue/ipyreact signatures; nothing is guessed from a plain str. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
maartenbreddels
force-pushed
the
feat/ipyvue-esm-modules
branch
from
July 5, 2026 08:15
576e18a to
a684fd7
Compare
maartenbreddels
added a commit
to widgetti/ipyreact
that referenced
this pull request
Jul 5, 2026
define_module(name, url="/static/bundle.mjs") imports the module from the url instead of shipping the code over the widget model (e.g. a bundle served from the app's static dir, cacheable and preloadable). Exactly one of module (a Path), code= or url= must be passed; a plain str still works as module code for backwards compatibility, with a DeprecationWarning. Note: under solara server define_module is patched by solara.server.esm, which needs the matching update (widgetti/solara#1169) for the new signature to apply there. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Matches ipyreact's own deprecation path: a plain str was module code in the released api, so it keeps working with a DeprecationWarning instead of a hard error. The ipyvue variant stays strict (never released). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
maartenbreddels
temporarily deployed
to
feat/ipyvue-esm-modules - solara-stable PR #1169
July 5, 2026 10:33 — with
Render
Destroyed
maartenbreddels
added a commit
to widgetti/ipyreact
that referenced
this pull request
Jul 5, 2026
define_module(name, url="/static/bundle.mjs") imports the module from the url instead of shipping the code over the widget model (e.g. a bundle served from the app's static dir, cacheable and preloadable). Exactly one of module (a Path), code= or url= must be passed; a plain str still works as module code for backwards compatibility, with a DeprecationWarning. Note: under solara server define_module is patched by solara.server.esm, which needs the matching update (widgetti/solara#1169) for the new signature to apply there. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
maartenbreddels
added a commit
to widgetti/ipyreact
that referenced
this pull request
Jul 5, 2026
define_module(name, url="/static/bundle.mjs") imports the module from the url instead of shipping the code over the widget model (e.g. a bundle served from the app's static dir, cacheable and preloadable). Exactly one of module (a Path), code= or url= must be passed; a plain str still works as module code for backwards compatibility, with a DeprecationWarning. Note: under solara server define_module is patched by solara.server.esm, which needs the matching update (widgetti/solara#1169) for the new signature to apply there. Co-Authored-By: Claude Fable 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.
Summary
Companion to widgetti/ipyvue#106 (ipyvue's vue3 branch gains
define_modulefor precompiled ESM bundles). This gives those modules the same server-side handling ipyreact modules get insolara/server/esm.py:Modulewidgets materialized per kernel inside the kernel contextcontext.restart()closed them, so in-place hot reload works (same fix as fix: make ES module (define_module) hot reload survive in-place app reload #1168)define_module(Path)registered with the reloader — rebuilding a bundle (vite build --watch) triggers a normal in-place reload_modulesmutation lockedEverything is
hasattr(ipyvue, "define_module")-gated, so it is a no-op on current ipyvue releases; the unit tests skip likewise until an ipyvue release ships the feature (verified 5/5 passing locally against the ipyvue#106 branch).Url modules: preload + content-hash caching
define_moduletakes exactly one ofmodule(aPath),code=orurl=(nothing is guessed from a plain str);url=serves the bundle from the app's static dir. For urls solara serves itself (/static/public/...):<link rel="modulepreload" href=".../bundle.mjs?v=<content-hash>">, so the browser fetches the bundle in parallel with kernel startup instead of waiting for the Module widget over the websocket (es-module-shims honors modulepreload in shim mode);esm_vue.versioned_url), so the preload is always a cache hit;StaticPublicserves the file withCache-Control: max-age=1y, immutableonly when the requested?vmatches the current content hash — rebuilds change the hash and therefore the url (automatic cache busting), stale hashes get normal headers (no poisoning). External urls and urls with their own query string pass through untouched.This generalizes the existing nbextension-hash mechanism (
nbextensions_hashes+ requirejsurlArgs) to app-served ES modules.Documentation
Includes a website howto page (
documentation/advanced/howto/vue-esm-components) with a complete runnable example (verified end to end locally against the ipyvue#106 branch: renders, click events reach Python, trait updates re-render) plus the vite workflow and the tag form.Usage (once ipyvue#106 is released)
solara.component_vuegainsesm_module/esm_exportas an alternative tovue_path:Same contract as a
.vue-file component: arguments become Vue data (overriding the component's owndata()placeholders),event_*arguments become callable methods. The howto page in this PR contains a complete no-build-step runnable example (verified end to end against the ipyvue#106 branch: renders, clicks reach Python, state re-renders) plus the vite workflow and the tag form.No template source goes over the wire and
vue/compiler-sfcis not needed at runtime for these components. Coexists with ipyreact modules on the same page (verified; registries are separate, the import-map namespace is shared so module names must be unique across libraries).