Skip to content

Commit 0329bfc

Browse files
fix(cjs): patch module.path for accurate cache ID
fixes #651
1 parent 44ed37f commit 0329bfc

File tree

4 files changed

+54
-2
lines changed

4 files changed

+54
-2
lines changed

.github/workflows/test.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
strategy:
1111
matrix:
1212
os: [ubuntu-latest, windows-latest]
13-
timeout-minutes: 5
13+
timeout-minutes: 10
1414

1515
steps:
1616
- name: Checkout

src/@types/module.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ declare module 'module' {
2020
export const _cache: NodeJS.Require['cache'];
2121

2222
export type Parent = {
23+
id: string;
2324

2425
/**
2526
* Can be null if the parent id is 'internal/preload' (e.g. via --require)

src/cjs/api/module-extensions.ts

+12
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import fs from 'node:fs';
2+
import path from 'node:path';
23
import Module from 'node:module';
34
import type { TransformOptions } from 'esbuild';
45
import { transformSync } from '../../utils/transform/index.js';
@@ -96,6 +97,17 @@ export const createExtensions = (
9697
return defaultLoader(module, filePath);
9798
}
9899

100+
/**
101+
* In new Module(), m.path = path.dirname(module.id) but module.id coming from
102+
* ESM resolver may be a data: path
103+
*
104+
* In these cases, we fix m.path to be the actual directory of the file
105+
*/
106+
// https://github.com/nodejs/node/blob/v22.8.0/lib/internal/modules/cjs/loader.js#L298
107+
if (module.id.startsWith('data:text/javascript,')) {
108+
module.path = path.dirname(cleanFilePath);
109+
}
110+
99111
// For tracking dependencies in watch mode
100112
if (parent?.send) {
101113
parent.send({

tests/specs/smoke.ts

+40-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const wasmPath = path.resolve('tests/fixtures/test.wasm');
1313
const wasmPathUrl = pathToFileURL(wasmPath).toString();
1414

1515
export default testSuite(async ({ describe }, { tsx, supports, version }: NodeApis) => {
16-
describe('Smoke', ({ describe }) => {
16+
describe('Smoke', ({ describe, test }) => {
1717
for (const packageType of packageTypes) {
1818
const isCommonJs = packageType === 'commonjs';
1919

@@ -481,5 +481,44 @@ export default testSuite(async ({ describe }, { tsx, supports, version }: NodeAp
481481
}
482482
});
483483
}
484+
485+
// https://github.com/privatenumber/tsx/issues/651
486+
test('resolves same relative path from CJS loaded by ESM', async ({ onTestFail }) => {
487+
await using fixture = await createFixture({
488+
'package.json': createPackageJson({ type: 'commonjs' }),
489+
a: {
490+
'index.ts': `
491+
import { value } from './value.js';
492+
493+
if (value !== 1) {
494+
throw new Error('Unexpected value');
495+
}
496+
`,
497+
'value.js': 'export const value = 1;',
498+
},
499+
b: {
500+
'index.ts': `
501+
import { value } from './value.js';
502+
503+
if (value !== 2) {
504+
throw new Error('Unexpected value');
505+
}
506+
`,
507+
'value.js': 'export const value = 2;',
508+
},
509+
'index.mjs': `
510+
import './a/index.js';
511+
import './b/index.js';
512+
`,
513+
});
514+
515+
const p = await tsx(['index.mjs'], {
516+
cwd: fixture.path,
517+
});
518+
onTestFail(() => {
519+
console.log(p);
520+
});
521+
expect(p.failed).toBe(false);
522+
});
484523
});
485524
});

0 commit comments

Comments
 (0)