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)], + }); + }); +});