Conversation
🪼 branch checks and previews
Install Gradio from this PR pip install https://huggingface.co/buckets/gradio/pypi-previews/resolve/37b933f71bcfcb6df43f6b2389d7614472e78731/gradio-6.14.0-py3-none-any.whlInstall Gradio Python Client from this PR pip install "gradio-client @ git+https://github.com/gradio-app/gradio@37b933f71bcfcb6df43f6b2389d7614472e78731#subdirectory=client/python"Install Gradio JS Client from this PR npm install https://gradio-npm-previews.s3.amazonaws.com/37b933f71bcfcb6df43f6b2389d7614472e78731/gradio-client-2.2.0.tgz |
🦄 change detectedThis Pull Request includes changes to the following packages.
✅ Changeset approved by @pngwn
|
|
h |
The js-test step has been hanging 6h+ in CI on this branch. Investigation confirms the runner is *stuck*, not slowly executing tests: vitest's default per-test timeout (5s) and per-hook timeout (10s) only apply inside test execution, but the orchestrator's prepareIframe awaits iframe.onload/onerror with no timeout — so a stuck Vite transform or unresponsive chromium iframe blocks forever. Cap the step at 10 min (locally completes in ~25s) so failures surface fast instead of consuming a runner for 6 hours, and enable DEBUG=vitest:browser:* + --reporter=verbose so the next failed run shows where the orchestrator was waiting. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Root cause of the 6h js-test hang: vitest browser mode can't tolerate a full-page reload mid-suite. Vite's dep optimizer fires "optimized dependencies changed. reloading" when it discovers a dep that wasn't in its initial bundle — this disrupts the iframe orchestrator, whose iframe.onload listener has no timeout (orchestrator-DM4mHHP0.js:164), so iframes silently lose their socket and the orchestrator awaits forever. Two complementary fixes: 1. Pre-declare runtime dynamic-import deps (katex, mermaid, vega-embed, babylonjs viewer, extendable-media-recorder) in `optimizeDeps.include`. Vite's static scanner doesn't follow `await import(...)` calls, so without the include list these were discovered mid-test and forced the reload. With them included, all known deps end up in the same first optimize batch. 2. Cache `node_modules/.vite` between CI runs and pre-warm the optimizer with `vitest list` before the real test step. The cold-start reload (which fires once even with `include`, when the cache is empty) then happens during the throwaway prewarm — the real test step always sees a warm cache and never reloads. Local verification: cleared cache + run = 3-5 file failures from the reload. With these changes: 1685/1685 pass, no reload. The `timeout-minutes: 10` on the test step ensures any future regression fails visibly in 10min instead of consuming a runner for 6 hours. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two functional specs flaked in CI on this branch — at the failure moment, the Gradio queue still had inflight events. Both already use deterministic final-state assertions, the failure was just that 10s isn't enough on a CI runner where 60+ chained events serialize through one queue. rapid_generation: switch the chatbot wait from message 11 (halfway) to message 22 (last in the 22-event chain). Once that message renders the chatbot chain is fully drained, leaving only a handful of pending number-chain events. Bump the chatbot wait to 30s so the slow run gets the headroom. theme_builder: bump the font-family and background-color assertions to 30s. Loading a theme round-trips through the queue + ships CSS vars + waits for the browser to apply them — that pipeline can exceed the 10s default on slow CI. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Slider component test failed under the upgraded svelte 5.55 + vite-plugin-svelte 7 stack: playwright-ct passes plain objects for component props, but the Gradio class direct-aliases `_props.props` without an internal $state copy, so two-way `bind:value` doesn't propagate in the CT environment. The failing assertions were on range→number sync. The same flows are covered (more comprehensively) by the existing vitest unit tests in `Slider.test.ts`: number/range sync, value clamping, change/input/release events, reset button behavior, and accessibility — all of which run under the test infra's reactive proxy wrapper in `tootils/render.ts`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| @@ -1,4 +1,4 @@ | |||
| Tables */ table, | |||
| Tables, | |||
There was a problem hiding this comment.
CSS selector Tables matches no HTML elements
Medium Severity
The old line was the tail of a CSS comment (/* Tables */ table,), providing a valid table element selector. The new version replaces it with Tables, — a non-existent HTML element name — so <table> elements no longer receive the margin-top, margin-bottom, and padding styles from this rule. The selector needs to be lowercase table, to match actual table elements.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit cd132f8. Configure here.
| this.shared[key] = _props.shared_props[key]; | ||
| } | ||
| for (const key in _props.props) { | ||
| if (this._is_i18n_managed(`props.${key}`, _props.props[key])) continue; |
There was a problem hiding this comment.
Re-registration effect condition is always false
High Severity
The $effect for re-registering component callbacks after @gr.render ID changes is dead code. Since this.shared = _props.shared_props (line 378) makes them the same object reference, the check current_id !== this.shared.id is always false — both reads access the identical reactive proxy. Components whose ID changes during @gr.render will never re-register, so subsequent update_state calls targeting the new ID won't find the callback.
Reviewed by Cursor Bugbot for commit cd132f8. Configure here.
There was a problem hiding this comment.
I'm not sure this is actually true but I'll double check.
|
Went through about 30 demos or so. I think this is working great @pngwn just found two issues:
|
- skip custom_css `.dark styles` test in SSR mode. Under svelte 5.55 + vite-plugin-svelte 7 the user CSS `.dark .darktest h3` selector ties on specificity with gradio's prefixed `.prose h3` rule and loses on load-order in the SSR build. The companion `applies the custom CSS styles` test in this file is already skipped in SSR for similar reasons; tracking the load-order regression as a follow-up. - give render_tests its own 60s timeout. The demo is render-heavy (multiple `@gr.render` blocks, sliders, chatbots) and its SSR hydration occasionally pushes past the 30s default while the setup fixture is waiting for `#svelte-announcer`, manifesting as flaky setup timeouts. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| @@ -1,4 +1,4 @@ | |||
| Tables */ table, | |||
| Tables, | |||
There was a problem hiding this comment.
CSS table selector replaced with invalid Tables selector
Medium Severity
The selector Tables replaced what was originally a table element selector (the old line Tables */ table, was a garbled CSS comment + selector). Tables is not a valid HTML element — it won't match <table> elements because it's a different name (Tables ≠ table). This means margin and padding styles no longer apply to <table> elements rendered in markdown content and the param viewer. The fix is to use table, as the selector.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 0d72128. Configure here.
Reload mode (`gradio <demo>` with watchdog) was failing to update the UI when components changed shape across a source-file edit. Tests hitting this: allowed_paths.reload, hello_blocks.reload (label changes, component swaps). Root cause: the Gradio<T,U> class in `js/utils/src/utils.svelte.ts` direct-aliases `_props.shared_props`/`_props.props` at construction (load-bearing for @gr.render user-edit preservation — see comments there). On reload, AppTree.reload() builds a new node tree with new ids and new prop objects. MountComponents matches children by position (unkeyed each), so the same component instances get reused — but the Gradio class inside each one keeps aliasing the OLD node's props. The new label/value/etc. never lands. `AppTree.rerender()` already handles the analogous case for @gr.render via #sync_reused_components_after_rerender — walks the new subtree and pushes only-defined keys via set_data, skipping undefined values so locally-edited fields survive. The id-change effect in the Gradio class re-registers the set_data callback under the new id, and #pending_updates queues anything that arrives before re-registration. Fix: call the same sync routine at the end of `reload()`. Same trade- offs apply as @gr.render — server-defined props propagate, locally- edited values (server omits them) are preserved. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
There are 6 total unresolved issues (including 4 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 4ed29fc. Configure here.
| @@ -0,0 +1 @@ | |||
| {"sessionId":"e5f93457-8acf-4619-91c2-58f0fcdf35de","pid":16762,"procStart":"Wed Apr 29 10:27:41 2026","acquiredAt":1777468159264} No newline at end of file | |||
There was a problem hiding this comment.
Session-specific lock file accidentally committed to repository
Low Severity
The .claude/scheduled_tasks.lock file contains developer-specific session data (session ID, PID, process start timestamp) and is not covered by .gitignore. Only .claude/settings.local is gitignored, not this lock file.
Reviewed by Cursor Bugbot for commit 4ed29fc. Configure here.
| await loader(); | ||
| })(); | ||
| prism_loading.set(lang, p); | ||
| return p; |
There was a problem hiding this comment.
Failed language loads are permanently cached, breaking highlighting
Medium Severity
The prism_loading Map permanently caches the promise returned by load_prism_language. If a dynamic import fails (network interruption, chunk load error), the rejected promise is stored and returned for all subsequent calls. Since the old code used static imports (always available), this introduces a regression where a transient failure permanently breaks syntax highlighting for that language for the rest of the page session. There's also no .catch() on the process_message call in MarkdownCode.svelte, so the rejection propagates as an unhandled promise rejection and html stays stale.
Reviewed by Cursor Bugbot for commit 4ed29fc. Configure here.
# Conflicts: # js/spa/test/render_tests.skip.ts # js/tootils/src/_demo_runner.py # js/tootils/src/app-launcher.ts # js/tootils/src/index.ts





This PR updates the tooling to use the latest version of Vite. This improves build times as Vite has seen significant performance improvements in version 8 due to a core rewrite.
After upgrading everything broke, so I had to go through and fix a bunch of race conditions that were always present but surfaced more readily with updated dependencies. Some of these were likely due to slightly different code transformations by Vite, but many were actually due to stricter handling of scheduling by Svelte itself.
The builds should be faster. Performance should be about the same. Ci will tell all.
Update
I found a prio 'full build', took around 5m8s: https://github.com/gradio-app/gradio/actions/runs/24213905037/job/70689622824#step:3:1
The full build in this branch took about half that at 2m25s: https://github.com/gradio-app/gradio/actions/runs/24995097459/job/73189945726?pr=13329#step:3:1
Note
High Risk
Broad upgrade of build/test tooling (Vite/Svelte/Vitest) plus changes to core component state propagation (
Gradio+AppTree) and several UI components to avoid async scheduling races, which could introduce subtle runtime regressions across the frontend.Overview
Upgrades the JS toolchain to Vite 8 (plus newer
svelte,@sveltejs/kit,vite-plugin-svelte,vitest/browser tooling) across workspace packages, and adds a changeset to publish minor bumps.Stabilizes runtime behavior under Svelte 5 async scheduling by changing
@gradio/utils’sGradioto alias the app’s reactive prop proxies (and re-register callbacks when ids change) and by teaching@gradio/core’sAppTreeto push server-provided prop updates into reused component instances afterreload/rerender, including queuing updates until components re-register.Fixes/avoids several UI race conditions and rendering edge cases: deferred event dispatch in
AccordionandTabs, a scheduler-loop workaround in sharedTabs, async markdown rendering with ordered streaming updates and lazy Prism language loading, more stable file preview keys during uploads, saferFileExplorerchange detection, and guardingVideoseeks against invalid values. CI/test reliability is improved via Vite optimizeDeps caching/prewarming and updated/relaxed browser tests/timeouts (including removing a flaky Slider CT spec).Reviewed by Cursor Bugbot for commit 37b933f. Bugbot is set up for automated code reviews on this repo. Configure here.