diff --git a/packages/metro-core/src/babel/transformer.js b/packages/metro-core/src/babel/transformer.js index bff4e037199..497370ba9f3 100644 --- a/packages/metro-core/src/babel/transformer.js +++ b/packages/metro-core/src/babel/transformer.js @@ -1,5 +1,5 @@ /* eslint-disable no-undef */ -const babelTransformer = require('__BABEL_TRANSFORMER_PATH__'); +const babelTransformer = require(__BABEL_TRANSFORMER_PATH__); const babelPlugins = __BABEL_PLUGINS__; /* eslint-enable no-undef */ diff --git a/packages/metro-core/src/plugin/__tests__/babel-transformer.test.ts b/packages/metro-core/src/plugin/__tests__/babel-transformer.test.ts new file mode 100644 index 00000000000..1124533c537 --- /dev/null +++ b/packages/metro-core/src/plugin/__tests__/babel-transformer.test.ts @@ -0,0 +1,62 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import { vol } from 'memfs'; +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { createBabelTransformer } from '../babel-transformer'; +import type { ModuleFederationConfigNormalized } from '../../types'; + +function createConfig(): ModuleFederationConfigNormalized { + return { + name: 'test-app', + filename: 'remote.js', + remotes: {}, + exposes: {}, + shared: {}, + shareStrategy: 'loaded-first', + plugins: [], + }; +} + +describe('createBabelTransformer', () => { + afterEach(() => { + vol.reset(); + vi.restoreAllMocks(); + }); + + it('escapes Windows paths for require()', () => { + const realReadFileSync = fs.readFileSync.bind(fs); + vi.spyOn(fs, 'readFileSync').mockImplementation(((filePath, options) => { + const targetPath = filePath.toString(); + if (vol.existsSync(targetPath)) { + return vol.readFileSync(targetPath, options as never); + } + return realReadFileSync(filePath, options as never); + }) as typeof fs.readFileSync); + vi.spyOn(fs, 'writeFileSync').mockImplementation((( + filePath, + data, + options, + ) => { + const targetPath = filePath.toString(); + vol.mkdirSync(path.dirname(targetPath), { recursive: true }); + vol.writeFileSync(targetPath, data, options as never); + }) as typeof fs.writeFileSync); + + const tmpDirPath = path.join('/virtual', '.mf'); + vol.mkdirSync(tmpDirPath, { recursive: true }); + const windowsPath = + 'C:\\Users\\someone\\project\\node_modules\\metro-babel-transformer\\src\\index.js'; + + const outputPath = createBabelTransformer({ + blacklistedPaths: [], + federationConfig: createConfig(), + originalBabelTransformerPath: windowsPath, + tmpDirPath, + enableInitializeCorePatching: false, + enableRuntimeRequirePatching: false, + }); + + const output = fs.readFileSync(outputPath, 'utf-8'); + expect(output).toContain(`require(${JSON.stringify(windowsPath)})`); + }); +}); diff --git a/packages/metro-core/src/plugin/babel-transformer.ts b/packages/metro-core/src/plugin/babel-transformer.ts index ecd1723b53c..72a86b0e573 100644 --- a/packages/metro-core/src/plugin/babel-transformer.ts +++ b/packages/metro-core/src/plugin/babel-transformer.ts @@ -41,7 +41,10 @@ export function createBabelTransformer({ ].filter(Boolean); const babelTransformer = transformerTemplate - .replaceAll('__BABEL_TRANSFORMER_PATH__', originalBabelTransformerPath) + .replaceAll( + '__BABEL_TRANSFORMER_PATH__', + JSON.stringify(originalBabelTransformerPath), + ) .replaceAll('__BABEL_PLUGINS__', JSON.stringify(plugins)); fs.writeFileSync(outputPath, babelTransformer, 'utf-8');