From b6e7368e9608a219dd8382034d9eb9f8822e376e Mon Sep 17 00:00:00 2001 From: KanteshMurade Date: Mon, 25 May 2026 23:03:10 +0530 Subject: [PATCH 1/2] fix(web): add Safari fallback for requestIdleCallback --- apps/web/app/entry.client.tsx | 4 +++ apps/web/core/lib/idle-task.ts | 49 ++++++++++++++++++++++------ apps/web/core/lib/polyfills/index.ts | 25 ++------------ 3 files changed, 46 insertions(+), 32 deletions(-) diff --git a/apps/web/app/entry.client.tsx b/apps/web/app/entry.client.tsx index 9c665ede072..8dc2a587717 100644 --- a/apps/web/app/entry.client.tsx +++ b/apps/web/app/entry.client.tsx @@ -8,6 +8,10 @@ import { startTransition, StrictMode } from "react"; import { hydrateRoot } from "react-dom/client"; import { HydratedRouter } from "react-router/dom"; +import polyfills from "@/lib/polyfills"; + +void polyfills; + startTransition(() => { hydrateRoot( document, diff --git a/apps/web/core/lib/idle-task.ts b/apps/web/core/lib/idle-task.ts index 34d070bfe40..cfc0e893fee 100644 --- a/apps/web/core/lib/idle-task.ts +++ b/apps/web/core/lib/idle-task.ts @@ -8,20 +8,49 @@ export type IdleTaskHandle = { cancel: () => void; }; +const requestIdleFallback = (callback: IdleRequestCallback): number => { + const start = Date.now(); + + return window.setTimeout(() => { + callback({ + didTimeout: false, + timeRemaining: () => Math.max(0, 50 - (Date.now() - start)), + }); + }, 1); +}; + +const cancelIdleFallback = (id: number) => { + window.clearTimeout(id); +}; + +export const requestIdle = (callback: IdleRequestCallback, options?: IdleRequestOptions): number => { + if (typeof window !== "undefined" && typeof window.requestIdleCallback === "function") + return window.requestIdleCallback(callback, options); + + return requestIdleFallback(callback); +}; + +export const cancelIdle = (id: number) => { + if (typeof window !== "undefined" && typeof window.cancelIdleCallback === "function") + return window.cancelIdleCallback(id); + + return cancelIdleFallback(id); +}; + +export const installIdleCallbackPolyfill = () => { + if (typeof window === "undefined") return; + + window.requestIdleCallback = window.requestIdleCallback ?? requestIdleFallback; + window.cancelIdleCallback = window.cancelIdleCallback ?? cancelIdleFallback; +}; + /** * Schedule lightweight work for idle time and return a cancel handle. * Falls back to setTimeout when requestIdleCallback is unavailable. */ -export const runIdleTask = (callback: () => void): IdleTaskHandle => { - if (typeof window !== "undefined" && typeof window.requestIdleCallback === "function") { - const idleId = window.requestIdleCallback(callback, { timeout: 300 }); - return { - cancel: () => window.cancelIdleCallback(idleId), - }; - } - - const timeoutId = window.setTimeout(callback, 0); +export const runIdleTask = (callback: IdleRequestCallback): IdleTaskHandle => { + const idleId = requestIdle(callback, { timeout: 300 }); return { - cancel: () => window.clearTimeout(timeoutId), + cancel: () => cancelIdle(idleId), }; }; diff --git a/apps/web/core/lib/polyfills/index.ts b/apps/web/core/lib/polyfills/index.ts index 2243dc620c2..fae765ebf8e 100644 --- a/apps/web/core/lib/polyfills/index.ts +++ b/apps/web/core/lib/polyfills/index.ts @@ -4,27 +4,8 @@ * See the LICENSE file for details. */ -if (typeof window !== "undefined" && window) { - // Add request callback polyfill to browser in case it does not exist - window.requestIdleCallback = - window.requestIdleCallback ?? - function (cb) { - const start = Date.now(); - return setTimeout(function () { - cb({ - didTimeout: false, - timeRemaining: function () { - return Math.max(0, 50 - (Date.now() - start)); - }, - }); - }, 1); - }; +import { installIdleCallbackPolyfill } from "@/lib/idle-task"; - window.cancelIdleCallback = - window.cancelIdleCallback ?? - function (id) { - clearTimeout(id); - }; -} +installIdleCallbackPolyfill(); -export {}; +export default true; From 201f84964dc6496465838ba866b238f2208308fb Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Thu, 28 May 2026 23:51:00 +0530 Subject: [PATCH 2/2] fix(web): use globalThis in idle-task fallbacks Switch idle-task fallback paths from window.* to globalThis.* so the fallback no longer crashes in environments where window is undefined. Also thread IdleRequestOptions through requestIdleFallback so the caller's timeout hint is honored when falling back. Addresses CodeRabbit review feedback on #9137. --- apps/web/core/lib/idle-task.ts | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/apps/web/core/lib/idle-task.ts b/apps/web/core/lib/idle-task.ts index cfc0e893fee..3d6db72b8f5 100644 --- a/apps/web/core/lib/idle-task.ts +++ b/apps/web/core/lib/idle-task.ts @@ -8,40 +8,38 @@ export type IdleTaskHandle = { cancel: () => void; }; -const requestIdleFallback = (callback: IdleRequestCallback): number => { +const requestIdleFallback = (callback: IdleRequestCallback, options?: IdleRequestOptions): number => { const start = Date.now(); - return window.setTimeout(() => { + return globalThis.setTimeout(() => { callback({ didTimeout: false, timeRemaining: () => Math.max(0, 50 - (Date.now() - start)), }); - }, 1); + }, options?.timeout ?? 1) as unknown as number; }; const cancelIdleFallback = (id: number) => { - window.clearTimeout(id); + globalThis.clearTimeout(id); }; export const requestIdle = (callback: IdleRequestCallback, options?: IdleRequestOptions): number => { - if (typeof window !== "undefined" && typeof window.requestIdleCallback === "function") - return window.requestIdleCallback(callback, options); + if (typeof globalThis.requestIdleCallback === "function") return globalThis.requestIdleCallback(callback, options); - return requestIdleFallback(callback); + return requestIdleFallback(callback, options); }; export const cancelIdle = (id: number) => { - if (typeof window !== "undefined" && typeof window.cancelIdleCallback === "function") - return window.cancelIdleCallback(id); + if (typeof globalThis.cancelIdleCallback === "function") return globalThis.cancelIdleCallback(id); return cancelIdleFallback(id); }; export const installIdleCallbackPolyfill = () => { - if (typeof window === "undefined") return; + if (typeof globalThis === "undefined") return; - window.requestIdleCallback = window.requestIdleCallback ?? requestIdleFallback; - window.cancelIdleCallback = window.cancelIdleCallback ?? cancelIdleFallback; + globalThis.requestIdleCallback = globalThis.requestIdleCallback ?? requestIdleFallback; + globalThis.cancelIdleCallback = globalThis.cancelIdleCallback ?? cancelIdleFallback; }; /**