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;