Skip to content

Commit 96d025d

Browse files
authored
fix(transformer): transpile mjs files from node_modules for CJS mode
1 parent 61a41b5 commit 96d025d

3 files changed

Lines changed: 48 additions & 9 deletions

File tree

src/legacy/ts-jest-transformer.spec.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ describe('TsJestTransformer', () => {
414414
},
415415
{
416416
filePath: 'my-project/node_modules/foo.mjs',
417-
expectedResult: `export default foo;`,
417+
expectedResult: `exports.default = foo;`,
418418
},
419419
])('should transpile js file from node_modules for CJS', ({ filePath, expectedResult }) => {
420420
const result = tr.process(
@@ -432,6 +432,20 @@ describe('TsJestTransformer', () => {
432432
expect(omitLeadingWhitespace(result.code)).toContain(expectedResult)
433433
})
434434

435+
it('should transpile .mjs file with import statements from node_modules to CJS without SyntaxError', () => {
436+
const result = tr.process(
437+
`
438+
import { LensList } from "./lens-list.mjs";
439+
export default LensList;
440+
`,
441+
'my-project/node_modules/rettime/build/index.mjs',
442+
baseTransformOptions,
443+
)
444+
445+
expect(omitLeadingWhitespace(result.code)).toContain(`require("./lens-list.mjs")`)
446+
expect(omitLeadingWhitespace(result.code)).not.toContain('import {')
447+
})
448+
435449
it('should transpile js file from node_modules for ESM', () => {
436450
const result = tr.process(
437451
`

src/legacy/ts-jest-transformer.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,11 +235,15 @@ export class TsJestTransformer implements SyncTransformer<TsJestTransformerOptio
235235
compilerOptions: {
236236
...configs.parsedTsConfig.options,
237237
module:
238-
transformOptions.supportsStaticESM && transformOptions.transformerConfig.useESM
238+
transformOptions.supportsStaticESM && transformOptions.transformerConfig?.useESM
239239
? ts.ModuleKind.ESNext
240240
: ts.ModuleKind.CommonJS,
241241
},
242-
fileName: sourcePath,
242+
// .mjs fileName causes ts.transpileModule to preserve ESM syntax even with module: CommonJS
243+
fileName:
244+
transformOptions.supportsStaticESM && transformOptions.transformerConfig?.useESM
245+
? sourcePath
246+
: sourcePath.replace(/\.mjs$/, '.js'),
243247
})
244248
result = {
245249
code: updateOutput(transpiledResult.outputText, sourcePath, transpiledResult.sourceMapText),

website/docs/guides/troubleshooting.md

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,20 +67,41 @@ SyntaxError: Cannot use import statement outside a module
6767

6868
### SOLUTION
6969

70-
One of the node modules hasn't the correct syntax for Jests execution step. It needs to
71-
be transformed first.
70+
One of the node modules doesn't have the correct syntax for Jest's execution step. It needs to be transformed first.
7271

73-
There is a good chance that the error message shows which module is affected:
72+
The error message usually shows which module is affected:
7473

7574
```shell
7675
SyntaxError: Cannot use import statement outside a module
7776
> 22 | import Component from "../../node_modules/some-module/lib";
7877
| ^
7978
```
8079

81-
In this case **some-module** is the problem and needs to be transformed.
82-
By adding the following line to the configuration file it will tell Jest which modules
83-
shouldnt be ignored during the transformation step:
80+
#### If the offending files are `.mjs` files
81+
82+
Use when individual files have a `.mjs` extension. Add a dedicated transform rule — ts-jest will transpile all `.mjs` files in `node_modules` to CommonJS without needing to list packages individually:
83+
84+
```ts title="jest.config.ts"
85+
import type { Config } from 'jest'
86+
import { createDefaultPreset } from 'ts-jest'
87+
88+
const presetConfig = createDefaultPreset()
89+
90+
const config: Config = {
91+
...presetConfig,
92+
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
93+
transform: {
94+
...presetConfig.transform,
95+
'^.+/node_modules/.+\\.mjs$': ['ts-jest', {}],
96+
},
97+
}
98+
99+
export default config
100+
```
101+
102+
#### If the offending package uses `"type": "module"` in its `package.json`
103+
104+
Use when a package declares `"type": "module"`, causing its `.js` files to be treated as ESM. Name each affected package explicitly in `transformIgnorePatterns`:
84105

85106
```ts title="jest.config.ts"
86107
import type { Config } from 'jest'

0 commit comments

Comments
 (0)