From 02ecf5838dc0f3701eac2f6a9f007dee383829b7 Mon Sep 17 00:00:00 2001 From: Matteo Pietro Dazzi Date: Tue, 8 Sep 2026 17:24:21 +0200 Subject: [PATCH] fix(repack): wrap babel-loader fallback value in an array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rspack's resolver and downstream tools that consume the resolved loader config (notably `RSDoctor`) expect `resolveLoader.fallback[name]` to be an array; a bare string triggered `Given napi value is not an array on NapiResolveOptions.fallback`. The record form is unchanged — only the value for `babel-loader` is now wrapped in a single-element array. This matches Rspack's `ResolveAlias` shape (`{ [x: string]: string | false | (string | false)[] }`) and Webpack's resolve loader fallback shape. Closes #1455 --- ...el-loader-resolve-loader-fallback-array.md | 5 ++++ packages/repack/src/plugins/BabelPlugin.ts | 3 +- .../src/plugins/__tests__/BabelPlugin.test.ts | 30 +++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 .changeset/babel-loader-resolve-loader-fallback-array.md create mode 100644 packages/repack/src/plugins/__tests__/BabelPlugin.test.ts diff --git a/.changeset/babel-loader-resolve-loader-fallback-array.md b/.changeset/babel-loader-resolve-loader-fallback-array.md new file mode 100644 index 000000000..837e1a17d --- /dev/null +++ b/.changeset/babel-loader-resolve-loader-fallback-array.md @@ -0,0 +1,5 @@ +--- +"@callstack/repack": patch +--- + +Fix `BabelPlugin` to set the `babel-loader` entry of `resolveLoader.fallback` as an array containing the resolved path, instead of a plain string. Rspack's resolver and downstream tools that consume the resolved loader config (e.g. `RSDoctor`) expect the value to be an array; a bare string triggered `Given napi value is not an array on NapiResolveOptions.fallback`. This still matches Rspack's `ResolveAlias` (`{ [x: string]: string | false | (string | false)[] }`) and Webpack's resolver loader fallback shape. \ No newline at end of file diff --git a/packages/repack/src/plugins/BabelPlugin.ts b/packages/repack/src/plugins/BabelPlugin.ts index 57df876ec..9bc8068ec 100644 --- a/packages/repack/src/plugins/BabelPlugin.ts +++ b/packages/repack/src/plugins/BabelPlugin.ts @@ -1,5 +1,6 @@ import type { Compiler as RspackCompiler } from '@rspack/core'; import type { Compiler as WebpackCompiler } from 'webpack'; + /** * Plugin that adds babel-loader fallback to resolveLoader configuration. * This ensures babel-loader can be resolved regardless of the package manager used, @@ -18,7 +19,7 @@ export class BabelPlugin { ...compiler.options.resolveLoader, fallback: { ...compiler.options.resolveLoader?.fallback, - 'babel-loader': require.resolve('babel-loader'), + 'babel-loader': [require.resolve('babel-loader')], }, }; } diff --git a/packages/repack/src/plugins/__tests__/BabelPlugin.test.ts b/packages/repack/src/plugins/__tests__/BabelPlugin.test.ts new file mode 100644 index 000000000..2f3d6ed68 --- /dev/null +++ b/packages/repack/src/plugins/__tests__/BabelPlugin.test.ts @@ -0,0 +1,30 @@ +import type { Compiler } from '@rspack/core'; +import { BabelPlugin } from '../BabelPlugin.js'; + +const compilerMock: { options: Compiler['options'] } = { + options: {} as Compiler['options'], +}; + +describe('BabelPlugin', () => { + it('sets resolveLoader.fallback[babel-loader] as an array entry', () => { + const pluginInstance = new BabelPlugin(); + pluginInstance.apply(compilerMock as unknown as Compiler); + + expect(compilerMock.options.resolveLoader?.fallback).toEqual({ + 'babel-loader': [expect.any(String)], + }); + }); + + it('preserves existing record fallback entries', () => { + compilerMock.options.resolveLoader = { + fallback: { 'foo-loader': '/path/to/foo-loader' }, + }; + const pluginInstance = new BabelPlugin(); + pluginInstance.apply(compilerMock as unknown as Compiler); + + expect(compilerMock.options.resolveLoader.fallback).toEqual({ + 'foo-loader': '/path/to/foo-loader', + 'babel-loader': [expect.any(String)], + }); + }); +});