diff --git a/src/index.js b/src/index.js index d00523e..546e395 100644 --- a/src/index.js +++ b/src/index.js @@ -70,28 +70,36 @@ function processResult(loaderContext, result) { export default function loader(content) { const options = this.getOptions(schema); const { executableFile } = options; - - let func; + const callback = this.async(); let exports; if (executableFile) { - // eslint-disable-next-line global-require,import/no-dynamic-require - func = require(executableFile); + try { + // eslint-disable-next-line global-require,import/no-dynamic-require + exports = require(executableFile); + } catch (error) { + callback(new Error(`Unable to require "${executableFile}": ${error}`)); + return; + } } else { try { exports = exec(content, this); } catch (error) { - throw new Error(`Unable to execute "${this.resource}": ${error}`); + callback(new Error(`Unable to execute "${this.resource}": ${error}`)); + return; } - - func = exports && exports.default ? exports.default : exports; } + const func = exports && exports.default ? exports.default : exports; + if (typeof func !== "function") { - throw new Error( - `Module "${this.resource}" does not export a function as default` + callback( + new Error( + `Module "${this.resource}" does not export a function as default` + ) ); + return; } let result; @@ -99,12 +107,11 @@ export default function loader(content) { try { result = func(options, this, content); } catch (error) { - throw new Error(`Module "${this.resource}" throw error: ${error}`); + callback(new Error(`Module "${this.resource}" throw error: ${error}`)); + return; } if (result && typeof result.then === "function") { - const callback = this.async(); - result .then((res) => processResult(this, res)) .catch((error) => { diff --git a/test/__snapshots__/executableFile.test.js.snap b/test/__snapshots__/executableFile.test.js.snap index c3adae3..446311f 100644 --- a/test/__snapshots__/executableFile.test.js.snap +++ b/test/__snapshots__/executableFile.test.js.snap @@ -1,5 +1,15 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`executableFile option should emit error: errors 1`] = ` +Array [ + "ModuleBuildError: Module build failed (from \`replaced original path\`): +Error: Unable to require \\"/test/fixtures/error-require.js\\": Error: This is a typical require() error", + "ChunkRenderError: Cannot read property 'get' of undefined", +] +`; + +exports[`executableFile option should emit error: warnings 1`] = `Array []`; + exports[`executableFile option should work: errors 1`] = `Array []`; exports[`executableFile option should work: result 1`] = ` diff --git a/test/executableFile.test.js b/test/executableFile.test.js index 0dd0da4..caf085a 100644 --- a/test/executableFile.test.js +++ b/test/executableFile.test.js @@ -46,4 +46,45 @@ describe("executableFile option", () => { ); expect(normalizeErrors(stats.compilation.errors)).toMatchSnapshot("errors"); }); + + it("should emit error", async () => { + const compiler = getCompiler( + "executableFileEntry.js", + {}, + { + module: { + rules: [ + { + test: /\.(json)$/i, + rules: [ + { + loader: require.resolve("./helpers/helperLoader.js"), + }, + { + loader: require.resolve("../src"), + options: { + executableFile: path.resolve( + __dirname, + "fixtures", + "error-require.js" + ), + }, + }, + ], + }, + { + test: /\.json$/i, + type: "asset/resource", + }, + ], + }, + } + ); + const stats = await compile(compiler); + + expect(normalizeErrors(stats.compilation.warnings)).toMatchSnapshot( + "warnings" + ); + expect(normalizeErrors(stats.compilation.errors)).toMatchSnapshot("errors"); + }); });