From df61c812fe32cec76ee67811e18d94f9f89d6866 Mon Sep 17 00:00:00 2001 From: KoloMl Date: Wed, 13 Aug 2025 16:48:27 +0400 Subject: [PATCH] Updated autorun logic to resolve issues with loading modules on Firefox Sometimes Firefox decides to load different groups of content scripts asynchronously, causing our trick with `requestAnimationFrame` to miss everything. To prevent this, I decided to just attempt to autorun everything on each definition using `setTimeout`. I've also tried to use `queueMicrotask` to put autorun logic right between different groups of modules, but this trick was only working on Firefox and completely breaking on Chromium. I sure love browsers! --- src/content/deps/amd.ts | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/content/deps/amd.ts b/src/content/deps/amd.ts index 9f4f525..759f4d5 100644 --- a/src/content/deps/amd.ts +++ b/src/content/deps/amd.ts @@ -2,21 +2,38 @@ import { amdLite } from "amd-lite"; const originalDefine = amdLite.define; +/** + * Throttle timer to make sure only one attempt at loading modules will run for a batch of loaded scripts. + */ +let throttledAutoRunTimer: NodeJS.Timeout | number | undefined; + +/** + * Schedule the automatic resolving of all waiting modules on the next available frame. + */ +function scheduleModulesAutoRun() { + clearTimeout(throttledAutoRunTimer); + + throttledAutoRunTimer = setTimeout(() => { + amdLite.resolveDependencies(Object.keys(amdLite.waitingModules)); + }); +} + amdLite.define = (name, dependencies, originalCallback) => { - return originalDefine(name, dependencies, function () { + originalDefine(name, dependencies, function () { const callbackResult = originalCallback(...arguments); // Workaround for the entry script not returning anything causing AMD-Lite to send warning about modules not // being loaded/not existing. return typeof callbackResult !== 'undefined' ? callbackResult : {}; - }) + }); + + // Schedule the auto run on the next available frame. Firefox and Chromium have a lot of differences in how they + // decide to execute content scripts. For example, Firefox might decide to skip a frame before attempting to load + // different groups of them. Chromium on the other hand doesn't have that issue, but it doesn't allow us to, for + // example, schedule a microtask to run the modules. + scheduleModulesAutoRun(); } amdLite.init({ publicScope: window }); - -// We don't have anything asynchronous, so it's safe to execute everything on the next frame. -requestAnimationFrame(() => { - amdLite.resolveDependencies(Object.keys(amdLite.waitingModules)) -});