diff --git a/.changeset/sharp-bars-peel.md b/.changeset/sharp-bars-peel.md new file mode 100644 index 000000000..1e460f16b --- /dev/null +++ b/.changeset/sharp-bars-peel.md @@ -0,0 +1,5 @@ +--- +"@callstack/repack": patch +--- + +Fix bundling with `babel-swc-loader` when `disableImportExportTransform` is set to `true` in RN babel preset diff --git a/packages/repack/src/loaders/babelSwcLoader/__tests__/babelSwcLoader.test.ts b/packages/repack/src/loaders/babelSwcLoader/__tests__/babelSwcLoader.test.ts index 1ad931261..e37eea8c4 100644 --- a/packages/repack/src/loaders/babelSwcLoader/__tests__/babelSwcLoader.test.ts +++ b/packages/repack/src/loaders/babelSwcLoader/__tests__/babelSwcLoader.test.ts @@ -1,4 +1,4 @@ -import { partitionTransforms } from '../babelSwcLoader.js'; +import { buildFinalSwcConfig, partitionTransforms } from '../babelSwcLoader.js'; type TransformEntry = [string, Record | undefined]; @@ -66,3 +66,27 @@ describe('partitionTransforms', () => { expect(result).toMatchSnapshot('empty arrays'); }); }); + +describe('buildFinalSwcConfig', () => { + it('uses module.type from swcConfig when transform-modules-commonjs is present', () => { + const result = buildFinalSwcConfig({ + swcConfig: { module: { type: 'commonjs' } }, + includedSwcTransforms: [], + lazyImports: false, + sourceType: 'module', + }); + + expect(result.module?.type).toBe('commonjs'); + }); + + it('falls back to es6 module.type when transform-modules-commonjs is not present', () => { + const result = buildFinalSwcConfig({ + swcConfig: {}, + includedSwcTransforms: [], + lazyImports: false, + sourceType: 'module', + }); + + expect(result.module?.type).toBe('es6'); + }); +}); diff --git a/packages/repack/src/loaders/babelSwcLoader/babelSwcLoader.ts b/packages/repack/src/loaders/babelSwcLoader/babelSwcLoader.ts index 2c5dc9cd4..1ce21f1a6 100644 --- a/packages/repack/src/loaders/babelSwcLoader/babelSwcLoader.ts +++ b/packages/repack/src/loaders/babelSwcLoader/babelSwcLoader.ts @@ -55,6 +55,41 @@ export function partitionTransforms( return { includedSwcTransforms, supportedSwcTransforms, swcConfig }; } +export interface BuildFinalSwcConfigOptions { + swcConfig: SwcLoaderOptions; + includedSwcTransforms: string[]; + lazyImports: boolean | string[]; + sourceType: 'module' | 'script' | undefined; +} + +export function buildFinalSwcConfig( + options: BuildFinalSwcConfigOptions +): SwcLoaderOptions { + const { swcConfig, includedSwcTransforms, lazyImports, sourceType } = options; + return { + ...swcConfig, + // set env based on babel transforms + env: { + // node supports everything and does not include + // any transforms by default, so it can as a template + targets: { node: 24 }, + include: includedSwcTransforms, + }, + // set lazy imports based on loader options + module: { + ...swcConfig.module, + lazy: lazyImports, + // if type is not set, this means that we are not using + // transform-modules-commonjs babel plugin, which can be disabled + // in babel config through `disableImportExportTransform` option in the RN preset + // we use 'es6' as a fallback here to achieve the desired behaviour of + // keeping ES modules as they are found in the source code + type: swcConfig.module?.type ?? 'es6', + }, + isModule: sourceType === 'module', + }; +} + export default async function babelSwcLoader( this: LoaderContext, source: string, @@ -118,23 +153,12 @@ export default async function babelSwcLoader( hermesParserOverrides: options.hermesParserOverrides, }); - const finalSwcConfig: SwcLoaderOptions = { - ...swcConfig, - // set env based on babel transforms - env: { - // node supports everything and does not include - // any transforms by default, so it can as a template - targets: { node: 24 }, - include: includedSwcTransforms, - }, - // set lazy imports based on loader options - module: { - ...swcConfig.module, - lazy: lazyImports, - type: swcConfig.module!.type, - }, - isModule: babelResult.sourceType === 'module', - }; + const finalSwcConfig = buildFinalSwcConfig({ + swcConfig, + includedSwcTransforms, + lazyImports, + sourceType: babelResult.sourceType, + }); const swcResult = swc.transformSync(babelResult?.code!, { ...finalSwcConfig,