vitest-dev / vitest

Next generation testing framework powered by Vite.
https://vitest.dev
MIT License
12.73k stars 1.15k forks source link

Differences in import behavior between vitest and vite-node #6601

Closed HexaField closed 3 hours ago

HexaField commented 5 hours ago

Describe the bug

We are trying to migrate from ts-node and mocha to vite-node and vitest for our server runtime and test runner, but are seeing differences in the behavior of vite-node as it runs servers vs tests.

When running tests, it behaves as expected according to the ESM specification, but when running as a server, it seems to handle import modules incorrectly.

Hookstate is a state management library that extends functionality of React. It overrides useEffect (among other functions) in order to update itself internally. When running vite-node from the CLI this behavior is not observed. (read more here https://github.com/avkonst/hookstate/issues/412)

In the provided reproduction, running npm run test to run vitest will successfully log that useEffect imported from React has been overridden by hookstate. When running npm run dev it will throw an error showing that it has not been overridden.

The behavior is also correct when running vite as the client/browser runtime.

Reproduction

https://stackblitz.com/edit/vitejs-vite-pnw4th?file=package.json&terminal=dev

https://github.com/HexaField/vite-node-vitest-esm-import-differences

Screenshot from 2024-10-01 12-14-30

System Info

System:
    OS: Linux 6.8 Ubuntu 22.04.4 LTS 22.04.4 LTS (Jammy Jellyfish)
    CPU: (16) x64 AMD Ryzen 7 5800X 8-Core Processor
    Memory: 48.25 GB / 62.72 GB
    Container: Yes
    Shell: 5.1.16 - /bin/bash
  Binaries:
    Node: 18.20.4 - ~/.nvm/versions/node/v18.20.4/bin/node
    npm: 10.8.2 - ~/.nvm/versions/node/v18.20.4/bin/npm
    bun: 1.1.27 - ~/.nvm/versions/node/v18.20.4/bin/bun
  Browsers:
    Brave Browser: 129.1.70.119
    Chrome: 128.0.6559.0
    Chromium: 129.0.6668.58

Used Package Manager

npm

Validations

hi-ogawa commented 3 hours ago

This is because Vitest has additional configuration for resolution: https://github.com/vitest-dev/vitest/blob/2a50464d58e98f58fed513971a570a952081bfef/packages/vitest/src/node/plugins/index.ts#L91-L93

For your use case (migration from ts-node), it's likely that doing the same would make sense. Adding this to vite.config.ts can fix your repro https://stackblitz.com/edit/vitejs-vite-eql4jh?file=vite.config.ts

HexaField commented 3 hours ago

This is because Vitest has additional configuration for resolution:

https://github.com/vitest-dev/vitest/blob/2a50464d58e98f58fed513971a570a952081bfef/packages/vitest/src/node/plugins/index.ts#L91-L93

For your use case (migration from ts-node), it's likely that doing the same would make sense. Adding this to vite.config.ts can fix your repro https://stackblitz.com/edit/vitejs-vite-eql4jh?file=vite.config.ts

Thanks so much. I have been digging into the code for a few days straight and hadn't found this. You are a life saver.

I'll leave it to you to triage and see if this should be implemented as a default to keep environments the same,

hi-ogawa commented 3 hours ago

I think we'll close the issue for now. If we get more reports about confusing resolutions, then we can revisit.

Btw, have you considered using tsx https://github.com/privatenumber/tsx instead of vite-node? Unless you need Vite plugin to customize something, tsx would be more closer to bare NodeJs execution and might be better fit for your use case.

HexaField commented 3 hours ago

I think we'll close the issue for now. If we get more reports about confusing resolutions, then we can revisit.

Btw, have you considered using tsx https://github.com/privatenumber/tsx instead of vite-node? Unless you need Vite plugin to customize something, tsx would be more closer to bare NodeJs execution and might be better fit for your use case.

I had trouble with it with conditional require calls that couldn't easily be turned into top level await import() calls since they relied on variable dynamic imports. But I will try it again at some point if I find any issues with vite-node.

HexaField commented 3 hours ago

Ok I just tried again, the immediate error I get is __dirname is not defined in ES module scope which I know is solvable, but I feel like if that failed many other things would. We have a very large and complicated project.

hi-ogawa commented 3 hours ago

Hmm, good point. vite-node currently allows cjs globals but tsx might be more strict about it. We don't necessary think such compat is desirable in all cases since it goes further away from esm semantics, but it certainly helps some scenarios. I'm glad it's working for your project.

https://github.com/vitest-dev/vitest/blob/2a50464d58e98f58fed513971a570a952081bfef/packages/vite-node/src/client.ts#L474-L479