From 571e6201695a1b3a5b01c007d1d875adddeecb9b Mon Sep 17 00:00:00 2001 From: greymoth-jp Date: Mon, 29 Jun 2026 08:57:16 +0900 Subject: [PATCH] fix(webpack): forward async load hook errors to the loader callback --- src/webpack/loaders/load.ts | 44 ++++++++++++-------- test/unit-tests/webpack/loaders/load.test.ts | 13 ++++++ 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/webpack/loaders/load.ts b/src/webpack/loaders/load.ts index e2fd10fa..4b2f03a6 100644 --- a/src/webpack/loaders/load.ts +++ b/src/webpack/loaders/load.ts @@ -17,22 +17,32 @@ export default async function load(this: LoaderContext, source: string, map const context = createContext(this) const { handler } = normalizeObjectHook('load', plugin.load) - const res = await handler.call( - Object.assign({}, createBuildContext({ - addWatchFile: (file) => { - this.addDependency(file) - }, - getWatchFiles: () => { - return this.getDependencies() - }, - }, this._compiler!, this._compilation, this), context), - normalizeAbsolutePath(id), - ) + try { + const res = await handler.call( + Object.assign({}, createBuildContext({ + addWatchFile: (file) => { + this.addDependency(file) + }, + getWatchFiles: () => { + return this.getDependencies() + }, + }, this._compiler!, this._compilation, this), context), + normalizeAbsolutePath(id), + ) - if (res == null) - callback(null, source, map) - else if (typeof res !== 'string') - callback(null, res.code, res.map ?? map) - else - callback(null, res, map) + if (res == null) + callback(null, source, map) + else if (typeof res !== 'string') + callback(null, res.code, res.map ?? map) + else + callback(null, res, map) + } + catch (error) { + if (error instanceof Error) { + callback(error) + } + else { + callback(new Error(String(error))) + } + } } diff --git a/test/unit-tests/webpack/loaders/load.test.ts b/test/unit-tests/webpack/loaders/load.test.ts index f8f182ed..9dd35d4a 100644 --- a/test/unit-tests/webpack/loaders/load.test.ts +++ b/test/unit-tests/webpack/loaders/load.test.ts @@ -62,4 +62,17 @@ describe('load function', () => { expect(mockCallback).toHaveBeenCalledWith(null, transformedCode, map) }) + + it('should call callback with the error if the handler throws', async () => { + const source = 'source code' + const map = 'source map' + const error = new Error('Handler error') + const pluginLoadHandler = vi.fn().mockRejectedValue(error) + mockLoaderContext.query.plugin.load = pluginLoadHandler + + await load.call(mockLoaderContext as any, source, map) + + expect(pluginLoadHandler).toHaveBeenCalled() + expect(mockCallback).toHaveBeenCalledWith(error) + }) })