From e659e7344d3b605fa9c2f22f2c1aef03c707207e Mon Sep 17 00:00:00 2001 From: SamTV12345 <40429738+samtv12345@users.noreply.github.com> Date: Mon, 25 May 2026 19:51:16 +0200 Subject: [PATCH] fix(jquery): promote module.exports onto window when UMD wrapper hit CJS branch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit jQuery's UMD wrapper at the top of vendors/jquery.ts has two branches: if (typeof module === "object" && typeof module.exports === "object") { module.exports = factory(global, true); // noGlobal=true } else { factory(global); // sets window.jQuery } The `factory(global, true)` form skips its own `window.jQuery = window.$ = jQuery` assignment (the `if (typeof noGlobal === "undefined")` guard inside the factory rejects when noGlobal is true). That was fine in develop's CJS world because consumers did `require('./vendors/jquery')` and got the function via module.exports. In our ESM/bundled world, specialpages.ts's runtime esbuild wraps every module in a CJS-style shim — `typeof module === "object"` becomes truthy inside the IIFE — so the CJS branch fires, but the ESM consumer (rjquery.ts) reads `window.jQuery` and finds it undefined: Error: Failed to initialize jQuery from ./vendors/jquery.js at rjquery.ts → cascades into every iframe-create path → no editor iframe → frontend tests time out waiting for ace_outer. Fix is purely defensive: after the IIFE, if window.jQuery is still missing AND module.exports holds the jQuery function (which it does on the CJS branch), promote it onto window. Original behavior is preserved on the non-CJS branch (window.jQuery already set, conditional no-ops). Also fix the export-default expression: the old `typeof window.$ === "object"` was wrong — jQuery is a function, not an object — and would have returned null even if globals were set. Replace with `window.$ ?? null`. Reproduced locally: a11y_dialogs.spec.ts goes from 0/20 timing out to 20/20 passing. The whole Playwright failure on PR #7605 collapses to this single root cause. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/static/js/vendors/jquery.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/static/js/vendors/jquery.ts b/src/static/js/vendors/jquery.ts index 8dfc6b84d..27d919755 100644 --- a/src/static/js/vendors/jquery.ts +++ b/src/static/js/vendors/jquery.ts @@ -10712,4 +10712,20 @@ return jQuery; } ); -export default (typeof window !== "undefined" && typeof window.$ === "object" ? window.$ : null); +// Defensive global assignment: under esbuild's runtime bundling +// (specialpages.ts builds /watch/pad on each request), the IIFE +// wrapper above sees a truthy `module` shim and takes the CJS branch, +// which sets module.exports but skips +// `window.jQuery = window.$ = jQuery`. Every consumer (rjquery.ts and +// friends) then throws "Failed to initialize jQuery". If jQuery +// landed in module.exports, promote it onto window. +if (typeof window !== "undefined" && !(window as any).jQuery) { + // @ts-ignore — `module` may be a runtime shim TS can't see in ESM context. + const mod: any = (typeof module === "object" && module && (module as any).exports) || null; + if (typeof mod === "function") { + (window as any).jQuery = mod; + (window as any).$ = mod; + } +} + +export default typeof window !== "undefined" ? ((window as any).$ ?? null) : null;