vitest icon indicating copy to clipboard operation
vitest copied to clipboard

Vitest cannot transpile with TypeScript `moduleResolution` set to `node16`

Open softcraft-development opened this issue 1 year ago • 16 comments

Describe the bug

When transpiling a trivial TypeScript library using the TypeScript-recommended module resolution (i.e.: "moduleResolution": "Node16", "module": "Node16"), tsc throws an error on Vitests' CommonJS version of the type declarations. These declarations in turn incorrectly reference the ES Module version of the declarations, which results in the error.

See https://github.com/softcraft-development/vitest-issue/blob/main/README.md for further details. It references https://www.typescriptlang.org/docs/handbook/modules/guides/choosing-compiler-options.html#im-writing-a-library, which in turn strongly recommends "moduleResolution": "Node16", "module": "Node16" as the tsconfig.json settings for Node libraries, both with and without the use of a bundler.

Correct handling of JavaScript/TypeScript modules is still overly complicated in 2024. In my own libraries I've taken to creating entirely separate ESM and CommonJS versions. It looks like Vitest is trying to mix the two strategies, which doesn't work under every circumstance.

Reproduction

  1. Clone the repository I created to demonstrate this issue: https://github.com/softcraft-development/vitest-issue
  2. Execute npm install to install the dependencies, including TypeScript and Vitest.
  3. Execute npm run node16

This generates the error:

node_modules/vitest/index.d.cts:1:15 - error TS1479: The current file is a CommonJS module whose imports will produce 'require' calls; however, the referenced file is an ECMAScript module and cannot be imported with 'require'. Consider writing a dynamic 'import("./dist/index.js")' call instead.

System Info

System:
    OS: macOS 12.6
    CPU: (8) x64 Intel(R) Core(TM) i5-8259U CPU @ 2.30GHz
    Memory: 19.16 MB / 16.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 18.18.2 - ~/.nvm/versions/node/v18.18.2/bin/node
    npm: 9.8.1 - ~/.nvm/versions/node/v18.18.2/bin/npm
    pnpm: 9.1.4 - ~/Library/pnpm/pnpm
  Browsers:
    Chrome: 125.0.6422.114
    Safari: 16.1
  npmPackages:
    vitest: ^1.6.0 => 1.6.0

Used Package Manager

npm

Validations

softcraft-development avatar Jun 02 '24 16:06 softcraft-development

Why would you compile Vitest tests into CJS? Vitest doesn't expose an actual CJS entry point, only a fake one for the old node target.

Vitest doesn't expect tests to be compiled, it transforms files on the fly.

sheremet-va avatar Jun 02 '24 20:06 sheremet-va

Why would you compile Vitest tests into CJS?

I'm not; I'm using tsc to do type checking on the test files (along side the source files). Note the noEmit: true setting in tsconfig.json.

softcraft-development avatar Jun 02 '24 20:06 softcraft-development

@softcraft-development have you tried renaming your .ts files to .mts? Your package type is CommonJS, but you are using ESM syntax in .ts files - that's what probably confuses TypeScript types resolution. To confirm this is the source of your issue, you can add "skipLibCheck": true and "noEmit": false to your tsconfig.json and run npm run node16, and you'll see that TypeScript emits CJS code in this case. Alternatively, you can keep the .ts file extensions but switch your package to ESM ("type": "module") if that works for you.

igordanchenko avatar Jul 18 '24 01:07 igordanchenko

I am also having this issue trying to use Node v20 and NodeNext module and moduleResolution values. I have tried a few combinations and couldn't get it to build unless I turn off lib checking like @igordanchenko noted above. Are there are non-bundler based tsconfig configurations that will build properly?

mhintzke avatar Aug 16 '24 16:08 mhintzke

@mhintzke chances are your source code module system contradicts your package module system and TypeScript file extensions.

Here are the questions that will help you figure out the correct combination.

  1. Do you use ESM syntax? (you import modules with the import statements)
  2. Is your package ESM or CommonJS?
  3. What file extensions do your TypeScript files use?

I assume you use ESM syntax, so I will cover only this scenario.

Here are the valid combinations:

  1. Your package is CommonJS (there is either no "type" field in your package.json or "type": "commonjs"). In this case, your TypeScript files must use .mts extensions, and you'll need to use .mjs extensions in your import statements.

  2. Your package is ESM ("type": "module" is present in your package.json). In this case, you can use .ts extensions for TypeScript files and .js extensions in your import statements. You can also use .mts / .mjs extensions as above, but they are really unnecessary in this case.

igordanchenko avatar Aug 16 '24 17:08 igordanchenko

@igordanchenko I appreciate the insight!

I will preface that I am in the middle of upgrading a large project from Node v10 and associated packages to Node v22 so a lot of the ESM stuff is pretty new to me. I will say that I fall in line with your second combination. I have package.json set to module type and use .ts file extensions with imports like import foo from './foo.js'. So I believe I have all of the necessary configuration elsewhere, it is just the tsconfig.json that I think needs to be adjusted to stop the error fromi happening.

Were you able to put skipLibCheck back to false at all? If so, what did you have to do besides the above to get it to work?

mhintzke avatar Aug 19 '24 15:08 mhintzke

@mhintzke

Were you able to put skipLibCheck back to false at all?

Yes, of course. But just keep in mind that TypeScript itself sets the skipLibCheck option to true when you create new project configuration with tsc --init.

If so, what did you have to do besides the above to get it to work?

Nothing really special. Here's a minimal example - https://stackblitz.com/edit/vitest-5820?file=tsconfig.json

igordanchenko avatar Aug 19 '24 15:08 igordanchenko

@igordanchenko Here is my setup:

package.json image

tsconfig.json image

vite.config.ts image

I only have a single explicitly import of vitest. The rest are all to vitest-mock-extended whicih provides utilities for doing mocking.

image

Yet I continue to get this error:

image

mhintzke avatar Aug 19 '24 16:08 mhintzke

@mhintzke your screenshot doesn't show the "type": "module" in your package.json. Can you confirm it's actually present?

It would also be helpful if you could provide a minimal repro on Stackblitz.

igordanchenko avatar Aug 19 '24 17:08 igordanchenko

@igordanchenko Yes, can confirm.

image

I will start to do that and see how it goes. Thanks

mhintzke avatar Aug 19 '24 17:08 mhintzke

@igordanchenko

Here is my reproduction. It definitely seems related to using vitest-mock-extended as once I added it and imported mock it blew up. I will go over to that package and see if I find any issues and if not, create one.

https://stackblitz.com/edit/vitest-5820-megvgc

mhintzke avatar Aug 20 '24 21:08 mhintzke

@softcraft-development are you using vitest-mock-extended by chance? My above stackblitz reproduces the issue by simply utilizing that library in any form. I created https://github.com/eratio08/vitest-mock-extended/issues/546 to hopefully get it looked at by them.

mhintzke avatar Aug 20 '24 21:08 mhintzke

@mhintzke I'm glad to hear you were able to identify your culprit. I took a quick look at vitest-mock-extended package.json and as far as I can tell, their module system and file extensions are all... backwards... The package is CommonJS, but they export ESM bundle with .js / .d.ts file extensions, while CJS bundle uses .cjs / .d.cts extensions. This makes no sense.

https://arethetypeswrong.github.io/?p=vitest-mock-extended%402.0.0

igordanchenko avatar Aug 20 '24 22:08 igordanchenko

@igordanchenko oooh I did not even notice that yet. Good catch and cool tool there. I guess we will just see what they say, but this is definitely not a vitest issue. I am curious to see what @softcraft-development says as it will change whether or not this issue is still valid or not.

Thanks for the help!

mhintzke avatar Aug 20 '24 23:08 mhintzke

I am curious to see what @softcraft-development says as it will change whether or not this issue is still valid or not.

It doesn't look like a valid issue at all. The original repro also has a mismatch between the module system and file extensions. I pointed this out in my very first comment on this thread.

igordanchenko avatar Aug 20 '24 23:08 igordanchenko

@igordanchenko ah, yes after re-reading it with new found knowledge I see what his issue was. You are correct, this should probably be closed

mhintzke avatar Aug 20 '24 23:08 mhintzke

Seems like it is a user error.

sheremet-va avatar Sep 06 '24 12:09 sheremet-va