diff --git a/packages/repack/src/modules/ScriptManager/ScriptManager.ts b/packages/repack/src/modules/ScriptManager/ScriptManager.ts index 25050bfd1..e068c932c 100644 --- a/packages/repack/src/modules/ScriptManager/ScriptManager.ts +++ b/packages/repack/src/modules/ScriptManager/ScriptManager.ts @@ -92,6 +92,7 @@ export class ScriptManager extends EventEmitter { } protected cache: Cache = {}; + protected scriptsPromises: Record | undefined> = {}; protected cacheInitialized = false; protected resolvers: [number, ScriptLocatorResolver][] = []; protected storage?: StorageApi; @@ -312,21 +313,30 @@ export class ScriptManager extends EventEmitter { caller?: string, webpackContext = getWebpackContext() ) { - let script = await this.resolveScript(scriptId, caller, webpackContext); - - try { - this.emit('loading', script.toObject()); - await this.nativeScriptManager.loadScript(scriptId, script.locator); - this.emit('loaded', script.toObject()); - } catch (error) { - const { code } = error as Error & { code: string }; - this.handleError( - error, - '[ScriptManager] Failed to load script:', - code ? `[${code}]` : '', - script.toObject() - ); + const uniqueId = Script.getScriptUniqueId(scriptId, caller); + if (this.scriptsPromises[uniqueId]) { + await this.scriptsPromises[uniqueId]; } + const loadProcess = async () => { + let script = await this.resolveScript(scriptId, caller, webpackContext); + + try { + this.emit('loading', script.toObject()); + await this.nativeScriptManager.loadScript(scriptId, script.locator); + this.emit('loaded', script.toObject()); + } catch (error) { + const { code } = error as Error & { code: string }; + this.handleError( + error, + '[ScriptManager] Failed to load script:', + code ? `[${code}]` : '', + script.toObject() + ); + } + }; + + this.scriptsPromises[uniqueId] = loadProcess(); + await this.scriptsPromises[uniqueId]; } /** @@ -344,20 +354,30 @@ export class ScriptManager extends EventEmitter { caller?: string, webpackContext = getWebpackContext() ) { - let script = await this.resolveScript(scriptId, caller, webpackContext); - - try { - this.emit('prefetching', script.toObject()); - await this.nativeScriptManager.prefetchScript(scriptId, script.locator); - } catch (error) { - const { code } = error as Error & { code: string }; - this.handleError( - error, - '[ScriptManager] Failed to prefetch script:', - code ? `[${code}]` : '', - script.toObject() - ); + const uniqueId = Script.getScriptUniqueId(scriptId, caller); + if (this.scriptsPromises[uniqueId]) { + await this.scriptsPromises[uniqueId]; } + const loadProcess = async () => { + let script = await this.resolveScript(scriptId, caller, webpackContext); + + try { + this.emit('prefetching', script.toObject()); + await this.nativeScriptManager.prefetchScript(scriptId, script.locator); + } catch (error) { + const { code } = error as Error & { code: string }; + this.handleError( + error, + '[ScriptManager] Failed to prefetch script:', + code ? `[${code}]` : '', + script.toObject() + ); + } + }; + + this.scriptsPromises[uniqueId] = loadProcess(); + + await this.scriptsPromises[uniqueId]; } /** @@ -376,7 +396,10 @@ export class ScriptManager extends EventEmitter { await this.initCache(); const ids = scriptIds.length ? scriptIds : Object.keys(this.cache); - ids.forEach((scriptId) => delete this.cache[scriptId]); + ids.forEach((scriptId) => { + delete this.cache[scriptId]; + delete this.scriptsPromises[scriptId]; + }); await this.saveCache(); await this.nativeScriptManager.invalidateScripts(scriptIds);