From 36e693bc69344a520a8c0d378f5f7a0cb6616360 Mon Sep 17 00:00:00 2001 From: Lukas Taegert-Atkinson Date: Thu, 30 Sep 2021 22:04:13 +0200 Subject: [PATCH] Abort the build for moduleParsed errors --- docs/05-plugin-development.md | 4 +++- src/ModuleLoader.ts | 11 ++++++---- .../plugin-error-module-parsed/_config.js | 22 +++++++++++++++++++ .../plugin-error-module-parsed/main.js | 13 +++++++++++ .../samples/preload-module/_config.js | 3 --- 5 files changed, 45 insertions(+), 8 deletions(-) create mode 100644 test/function/samples/plugin-error-module-parsed/_config.js create mode 100644 test/function/samples/plugin-error-module-parsed/main.js diff --git a/docs/05-plugin-development.md b/docs/05-plugin-development.md index 22f2c476eca..d3356dcf4e1 100644 --- a/docs/05-plugin-development.md +++ b/docs/05-plugin-development.md @@ -687,7 +687,9 @@ Returns `null` if the module id cannot be found. Get ids of the files which has been watched previously. Include both files added by plugins with `this.addWatchFile` and files added implicitly by rollup during the build. -#### `this.load({id: string, moduleSideEffects?: boolean | 'no-treeshake' | null, syntheticNamedExports?: boolean | string | null, meta?: {[plugin: string]: any} | null}) => Promise` +#### `this.load` + +**Type:** `({id: string, moduleSideEffects?: boolean | 'no-treeshake' | null, syntheticNamedExports?: boolean | string | null, meta?: {[plugin: string]: any} | null}) => Promise` Loads and parses the module corresponding to the given id, attaching additional meta information to the module if provided. This will trigger the same [`load`](guide/en/#load), [`transform`](guide/en/#transform) and [`moduleParsed`](guide/en/#moduleparsed) hooks that would be triggered if the module were imported by another module. diff --git a/src/ModuleLoader.ts b/src/ModuleLoader.ts index d2894e5e8c8..0649d0b0951 100644 --- a/src/ModuleLoader.ts +++ b/src/ModuleLoader.ts @@ -366,16 +366,19 @@ export class ModuleLoader { .then(([resolveStaticDependencyPromises, resolveDynamicImportPromises]) => Promise.all([...resolveStaticDependencyPromises, ...resolveDynamicImportPromises]) ) - .then(() => this.pluginDriver.hookParallel('moduleParsed', [module.info])) - .catch(() => { - /* rejections thrown here are also handled within PluginDriver - they are safe to ignore */ - }); + .then(() => this.pluginDriver.hookParallel('moduleParsed', [module.info])); + loadAndResolveDependenciesPromise.catch(() => { + /* avoid unhandled promise rejections */ + }); + if (isPreload) { this.moduleLoadingState.set(module, { loadAndResolveDependenciesPromise, loadPromise }); await loadAndResolveDependenciesPromise; } else { this.moduleLoadingState.set(module, { loadAndResolveDependenciesPromise, loadPromise: null }); await this.fetchModuleDependencies(module, ...(await loadPromise)); + // To handle errors when resolving dependencies or in moduleParsed + await loadAndResolveDependenciesPromise; } return module; } diff --git a/test/function/samples/plugin-error-module-parsed/_config.js b/test/function/samples/plugin-error-module-parsed/_config.js new file mode 100644 index 00000000000..b2190253239 --- /dev/null +++ b/test/function/samples/plugin-error-module-parsed/_config.js @@ -0,0 +1,22 @@ +const path = require('path'); + +module.exports = { + description: 'errors in moduleParsed abort the build', + options: { + plugins: [ + { + name: 'testPlugin', + moduleParsed() { + throw new Error('broken'); + } + } + ] + }, + error: { + code: 'PLUGIN_ERROR', + hook: 'moduleParsed', + message: 'broken', + plugin: 'testPlugin', + watchFiles: [path.join(__dirname, 'main.js')] + } +}; diff --git a/test/function/samples/plugin-error-module-parsed/main.js b/test/function/samples/plugin-error-module-parsed/main.js new file mode 100644 index 00000000000..69b8f8f7946 --- /dev/null +++ b/test/function/samples/plugin-error-module-parsed/main.js @@ -0,0 +1,13 @@ +let effect = false; + +var b = { + get a() { + effect = true; + } +}; + +function X() {} +X.prototype = b; +new X().a; + +assert.ok(effect); diff --git a/test/function/samples/preload-module/_config.js b/test/function/samples/preload-module/_config.js index 0deeb0df43e..1c2eddf7eea 100644 --- a/test/function/samples/preload-module/_config.js +++ b/test/function/samples/preload-module/_config.js @@ -9,9 +9,6 @@ const transformedModules = []; const parsedModules = []; module.exports = { - solo: true, - // TODO Lukas test - // * moduleParsed errors abort the build (or other hook errors) description: 'allows pre-loading modules via this.load', options: { plugins: [