diff --git a/src/index.ts b/src/index.ts index bca7d3bde..ffb858101 100644 --- a/src/index.ts +++ b/src/index.ts @@ -751,7 +751,9 @@ export function create(rawOptions: CreateOptions = {}): Service { 'Transformers function is unavailable in "--transpile-only"' ); } - let customTranspiler: Transpiler | undefined = undefined; + let createTranspiler: + | ((compilerOptions: TSCommon.CompilerOptions) => Transpiler) + | undefined; if (transpiler) { if (!transpileOnly) throw new Error( @@ -762,11 +764,21 @@ export function create(rawOptions: CreateOptions = {}): Service { const transpilerOptions = typeof transpiler === 'string' ? {} : transpiler[1] ?? {}; const transpilerPath = projectLocalResolveHelper(transpilerName, true); - const transpilerFactory: TranspilerFactory = require(transpilerPath).create; - customTranspiler = transpilerFactory({ - service: { options, config, projectLocalResolveHelper }, - ...transpilerOptions, - }); + const transpilerFactory = require(transpilerPath) + .create as TranspilerFactory; + createTranspiler = function (compilerOptions) { + return transpilerFactory({ + service: { + options, + config: { + ...config, + options: compilerOptions, + }, + projectLocalResolveHelper, + }, + ...transpilerOptions, + }); + }; } /** @@ -1277,6 +1289,7 @@ export function create(rawOptions: CreateOptions = {}): Service { const compilerOptions = { ...config.options }; if (overrideModuleType !== undefined) compilerOptions.module = overrideModuleType; + let customTranspiler = createTranspiler?.(compilerOptions); return (code: string, fileName: string): SourceOutput => { let result: _ts.TranspileOutput; if (customTranspiler) { diff --git a/src/test/index.spec.ts b/src/test/index.spec.ts index 19c0913b2..b69670a64 100644 --- a/src/test/index.spec.ts +++ b/src/test/index.spec.ts @@ -1197,39 +1197,46 @@ test.suite('ts-node', (test) => { expect(stdout).toBe(''); }); - async function runModuleTypeTest(project: string, ext: string) { - const { err, stderr, stdout } = await exec( - `${CMD_ESM_LOADER_WITHOUT_PROJECT} ./module-types/${project}/test.${ext}`, - { - env: { - ...process.env, - TS_NODE_PROJECT: `./module-types/${project}/tsconfig.json`, - }, - } - ); - expect(err).toBe(null); - expect(stdout).toBe(`Failures: 0\n`); - } - - test('moduleTypes should allow importing CJS in an otherwise ESM project', async (t) => { - // A notable case where you can use ts-node's CommonJS loader, not the ESM loader, in an ESM project: - // when loading a webpack.config.ts or similar config - const { err, stderr, stdout } = await exec( - `${CMD_TS_NODE_WITHOUT_PROJECT_FLAG} --project ./module-types/override-to-cjs/tsconfig.json ./module-types/override-to-cjs/test-webpack-config.cjs` - ); - expect(err).toBe(null); - expect(stdout).toBe(``); - - await runModuleTypeTest('override-to-cjs', 'cjs'); - if (semver.gte(process.version, '14.13.1')) - await runModuleTypeTest('override-to-cjs', 'mjs'); - }); - - test('moduleTypes should allow importing ESM in an otherwise CJS project', async (t) => { - await runModuleTypeTest('override-to-esm', 'cjs'); - // Node 14.13.0 has a bug(?) where it checks for ESM-only syntax *before* we transform the code. - if (semver.gte(process.version, '14.13.1')) - await runModuleTypeTest('override-to-esm', 'mjs'); + test.suite('moduleTypes', (test) => { + suite('with vanilla ts transpilation', 'tsconfig.json'); + suite('with third-party-transpiler', 'tsconfig-swc.json'); + function suite(name: string, tsconfig: string) { + test.suite(name, (test) => { + test('supports CJS webpack.config.ts in an otherwise ESM project', async (t) => { + // A notable case where you can use ts-node's CommonJS loader, not the ESM loader, in an ESM project: + // when loading a webpack.config.ts or similar config + const { err, stdout } = await exec( + `${CMD_TS_NODE_WITHOUT_PROJECT_FLAG} --project ./module-types/override-to-cjs/${tsconfig} ./module-types/override-to-cjs/test-webpack-config.cjs` + ); + expect(err).toBe(null); + expect(stdout).toBe(``); + }); + test('should allow importing CJS in an otherwise ESM project', async (t) => { + await run('override-to-cjs', tsconfig, 'cjs'); + if (semver.gte(process.version, '14.13.1')) + await run('override-to-cjs', tsconfig, 'mjs'); + }); + test('should allow importing ESM in an otherwise CJS project', async (t) => { + await run('override-to-esm', tsconfig, 'cjs'); + // Node 14.13.0 has a bug(?) where it checks for ESM-only syntax *before* we transform the code. + if (semver.gte(process.version, '14.13.1')) + await run('override-to-esm', tsconfig, 'mjs'); + }); + }); + } + async function run(project: string, config: string, ext: string) { + const { err, stderr, stdout } = await exec( + `${CMD_ESM_LOADER_WITHOUT_PROJECT} ./module-types/${project}/test.${ext}`, + { + env: { + ...process.env, + TS_NODE_PROJECT: `./module-types/${project}/${config}`, + }, + } + ); + expect(err).toBe(null); + expect(stdout).toBe(`Failures: 0\n`); + } }); } diff --git a/tests/module-types/override-to-cjs/tsconfig-swc.json b/tests/module-types/override-to-cjs/tsconfig-swc.json new file mode 100644 index 000000000..ca7aae1eb --- /dev/null +++ b/tests/module-types/override-to-cjs/tsconfig-swc.json @@ -0,0 +1,15 @@ +{ + "ts-node": { + "swc": true, + "moduleTypes": { + "webpack.config.ts": "cjs", + // Test that subsequent patterns override earlier ones + "src/cjs-subdir/**/*": "esm", + "src/cjs-subdir": "cjs", + "src/cjs-subdir/esm-exception.ts": "esm" + } + }, + "compilerOptions": { + "module": "ES2015" + } +} diff --git a/tests/module-types/override-to-esm/tsconfig-swc.json b/tests/module-types/override-to-esm/tsconfig-swc.json new file mode 100644 index 000000000..35a08fc62 --- /dev/null +++ b/tests/module-types/override-to-esm/tsconfig-swc.json @@ -0,0 +1,14 @@ +{ + "ts-node": { + "swc": true, + "moduleTypes": { + // Test that subsequent patterns override earlier ones + "src/esm-subdir/**/*": "cjs", + "src/esm-subdir": "esm", + "src/esm-subdir/cjs-exception.ts": "cjs" + } + }, + "compilerOptions": { + "module": "CommonJS" + } +}