From cb1419afecb288f0eb0d3a992d414c46b86b5e15 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Sat, 11 Dec 2021 07:06:05 +0100 Subject: [PATCH] Make sure this.load waits for modules that are already loading (#4296) --- src/ModuleLoader.ts | 39 ++++++++++--------- .../samples/preload-loading-module/_config.js | 20 ++++++++++ .../samples/preload-loading-module/main.js | 1 + 3 files changed, 41 insertions(+), 19 deletions(-) create mode 100644 test/function/samples/preload-loading-module/_config.js create mode 100644 test/function/samples/preload-loading-module/main.js diff --git a/src/ModuleLoader.ts b/src/ModuleLoader.ts index 3442b5f1061..0d774a8bad6 100644 --- a/src/ModuleLoader.ts +++ b/src/ModuleLoader.ts @@ -56,7 +56,8 @@ type ResolveDynamicDependencyPromise = Promise< type LoadModulePromise = Promise< [ resolveStaticDependencies: ResolveStaticDependencyPromise[], - resolveDynamicDependencies: ResolveDynamicDependencyPromise[] + resolveDynamicDependencies: ResolveDynamicDependencyPromise[], + loadAndResolveDependencies: Promise ] >; @@ -66,6 +67,7 @@ export class ModuleLoader { private readonly indexedEntryModules: { index: number; module: Module }[] = []; private latestLoadModulesPromise: Promise = Promise.resolve(); private moduleLoadPromises = new Map(); + private modulesWithLoadedDependencies = new Set(); private nextEntryModuleIndex = 0; private readQueue = new Queue(); @@ -353,7 +355,8 @@ export class ModuleLoader { this.graph.watchFiles[id] = true; const loadPromise: LoadModulePromise = this.addModuleSource(id, importer, module).then(() => [ this.getResolveStaticDependencyPromises(module), - this.getResolveDynamicImportPromises(module) + this.getResolveDynamicImportPromises(module), + loadAndResolveDependenciesPromise ]); const loadAndResolveDependenciesPromise = loadPromise .then(([resolveStaticDependencyPromises, resolveDynamicImportPromises]) => @@ -363,14 +366,10 @@ export class ModuleLoader { loadAndResolveDependenciesPromise.catch(() => { /* avoid unhandled promise rejections */ }); - - if (isPreload) { - this.moduleLoadPromises.set(module, loadPromise); - await loadPromise; - } else { - await this.fetchModuleDependencies(module, ...(await loadPromise)); - // To handle errors when resolving dependencies or in moduleParsed - await loadAndResolveDependenciesPromise; + this.moduleLoadPromises.set(module, loadPromise); + const resolveDependencyPromises = await loadPromise; + if (!isPreload) { + await this.fetchModuleDependencies(module, ...resolveDependencyPromises); } return module; } @@ -378,13 +377,20 @@ export class ModuleLoader { private async fetchModuleDependencies( module: Module, resolveStaticDependencyPromises: ResolveStaticDependencyPromise[], - resolveDynamicDependencyPromises: ResolveDynamicDependencyPromise[] + resolveDynamicDependencyPromises: ResolveDynamicDependencyPromise[], + loadAndResolveDependenciesPromise: Promise ) { + if (this.modulesWithLoadedDependencies.has(module)) { + return; + } + this.modulesWithLoadedDependencies.add(module); await Promise.all([ this.fetchStaticDependencies(module, resolveStaticDependencyPromises), this.fetchDynamicDependencies(module, resolveDynamicDependencyPromises) ]); module.linkImports(); + // To handle errors when resolving dependencies or in moduleParsed + await loadAndResolveDependenciesPromise; } private fetchResolvedDependency( @@ -521,10 +527,9 @@ export class ModuleLoader { } private async handleExistingModule(module: Module, isEntry: boolean, isPreload: boolean) { - const loadPromise = this.moduleLoadPromises.get(module); + const loadPromise = this.moduleLoadPromises.get(module)!; if (isPreload) { - await loadPromise; - return; + return loadPromise; } if (isEntry) { module.info.isEntry = true; @@ -534,11 +539,7 @@ export class ModuleLoader { } module.implicitlyLoadedAfter.clear(); } - if (loadPromise) { - this.moduleLoadPromises.delete(module); - await this.fetchModuleDependencies(module, ...(await loadPromise)); - } - return; + return this.fetchModuleDependencies(module, ...(await loadPromise)); } private handleResolveId( diff --git a/test/function/samples/preload-loading-module/_config.js b/test/function/samples/preload-loading-module/_config.js new file mode 100644 index 00000000000..88c4149dbdc --- /dev/null +++ b/test/function/samples/preload-loading-module/_config.js @@ -0,0 +1,20 @@ +const assert = require('assert'); + +let preloadedCode; + +module.exports = { + description: 'waits for pre-loaded modules that are currently loading', + options: { + plugins: [ + { + name: 'test-plugin', + load(id) { + this.load({ id }).then(({ code }) => (preloadedCode = code)); + }, + buildEnd(err) { + assert.strictEqual(preloadedCode, 'assert.ok(true);\n'); + } + } + ] + } +}; diff --git a/test/function/samples/preload-loading-module/main.js b/test/function/samples/preload-loading-module/main.js new file mode 100644 index 00000000000..cc1d88a24fa --- /dev/null +++ b/test/function/samples/preload-loading-module/main.js @@ -0,0 +1 @@ +assert.ok(true);