vitest-dev / vitest

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

Dependency resolution difference between vitest and vite #1562

Closed dennisMeeQ closed 2 years ago

dennisMeeQ commented 2 years ago

Describe the bug

When using Material UI, we have the option to exchange the css-in-js solution from emotion to styled-components by basically aliasing the styled-components wrapper onto the emotion wrapper.

This works perfectly fine in vite (see step 2 in the stackblitz repro below) but when using the same setup with vitest (see step 3) it crashes because it cannot resolve the peer-dependency to @emotion/styled. This peer-dependency is technically not needed because styled-components and @mui/styled-engine-sc serve as replacements but vitest is unhappy about it.

I can work around this issue by installing @emotion/styled as dev dependency but that is probably not an ideal solution.

Reproduction

  1. https://stackblitz.com/edit/vitejs-vite-pxpnnv
  2. Run npm start => the app starts and the styled-components CSS works
  3. Run npm run test => the test crashes with a dependency resolution problem:
 FAIL  src/Foo/foo.test.tsx [ src/Foo/foo.test.tsx ]
Error: Cannot find module '@emotion/styled'
Require stack:
- /home/projects/vitejs-vite-pxpnnv/node_modules/@mui/styled-engine/node/index.js
- /home/projects/vitejs-vite-pxpnnv/node_modules/@mui/system/index.js
- /home/projects/vitejs-vite-pxpnnv/node_modules/@mui/material/node/styles/adaptV4Theme.js
- /home/projects/vitejs-vite-pxpnnv/node_modules/@mui/material/node/styles/index.js
- /home/projects/vitejs-vite-pxpnnv/node_modules/@mui/x-date-pickers/node/CalendarPicker/CalendarPicker.js
- /home/projects/vitejs-vite-pxpnnv/node_modules/@mui/x-date-pickers/node/CalendarPicker/index.js

System Info

System:
    OS: macOS 12.4
    CPU: (10) arm64 Apple M1 Max
    Memory: 3.31 GB / 64.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 16.15.1 - ~/.nvm/versions/node/v16.15.1/bin/node
    npm: 8.11.0 - ~/.nvm/versions/node/v16.15.1/bin/npm
  Browsers:
    Chrome: 103.0.5060.53
    Firefox: 99.0
    Safari: 15.5
  npmPackages:
    vite: ^2.9.9 => 2.9.13 
    vitest: latest => 0.16.0

Used Package Manager

npm

Validations

sheremet-va commented 2 years ago

You will need to install it, or use deps.inline for problematic dependencies: https://vitest.dev/config/#deps

You should expect some level of differences, because Vite runs your code in browser, but Vitest runs your code in Node. Stack you see tells me that Native Node resolution kicks in. If you don't want this behaviour, use test.deps.inline or ssr.noExternal.

dennisMeeQ commented 2 years ago

Thanks

matheusmb commented 1 year ago

Hi @dennisMeeQ , could share your solution? I tried to add @emotion/styed to test.deps.inline but it is not working.

export default defineConfig({
  plugins: [react(), tsconfigPaths()],
  test: {
    environment: 'jsdom',
    globals: true,
    setupFiles: './test/vitest.setup.ts',
    deps: {
      inline: [
        '@emotion/styled'
      ],
    },
  },
});
dennisMeeQ commented 1 year ago

Hmm, quite some time ago. But iirc the solution in the end was to simply live with the workaround described in my original description: Install @emotion/styled as dev dependency

grahamhency commented 1 year ago

@sheremet-va I'd like to request this issue reopened as I'm experiencing the exact same issue as @dennisMeeQ. Same repo setup and even on latest versions of Vite/Vitest/Mui.

The deps.inline suggestion does not work in this case. For context, MUI offers two options for their styled components system: @emotion/styled and styled-components. By default they prefer @emotion/styled, but we use styled-components in our app already so we're opting to use it within MUI. Here are some docs from MUI on this.

I've setup the appropriate alias in my tsconfig:

{
  "compilerOptions": {
    "paths": {
      "@mui/styled-engine": ["@mui/styled-engine-sc"]
    }
  }
}

And additionally have added it to the resolve.alias portion of our vite.config.ts:

alias: [
  { find: '@mui/styled-engine', replacement: '@mui/styled-engine-sc' },
],

Running vite serve works just fine, but running vitest it fails with this warning:

Vitest caught 1 unhandled error during the test run.
This might cause false positive tests. Resolve unhandled errors to make sure your tests are not affected.
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Unhandled Rejection
 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Error: Cannot find module '@emotion/styled'
Require stack:
- {repo}/node_modules/@mui/styled-engine/node/index.js

If we look at our node_modules we can see that the @emotion/styled import is coming from @mui/styled-engine. Screen Shot 2023-03-29 at 4 13 18 PM

So according to the Vite & Typescript aliases, @mui/styled-engine should be replaced with @mui/styled-engine-sc, but it appears it's not in Vitest.

I'd really prefer to not include another styled library into the app as a workaround. With all this, any other suggestions?

sheremet-va commented 1 year ago

I'd really prefer to not include another styled library into the app as a workaround. With all this, any other suggestions?

Try enabling deps.experimentalOptimizer.

grahamhency commented 1 year ago

@sheremet-va thanks for the suggestion, unfortunately it results in the same behavior. I did try enabling deps.registerNodeLoader and that got me a little further.

From the docs:

Use experimental Node loader to resolve imports inside externalized files, using Vite resolve algorithm.

If disabled, your alias and .resolveId won't affect imports inside externalized packages (by default, node_modules).

Looks like enabling that allows Vitest to use Vite's resolve algorithm within the node_modules. However that results in this error.. which I'm not sure is progress or just different lol.

ReferenceError: exports is not defined in ES module scope

Is there perhaps some combination of things I can enable that you might know of?

sheremet-va commented 1 year ago

Is there perhaps some combination of things I can enable that you might know of?

I think the best way is to follow Vite's recommendation about SSR aliases (which is what is being used here, unless experimentalOptimizer is enabled): https://vitejs.dev/config/shared-options.html#resolve-alias

grahamhency commented 1 year ago

@sheremet-va ahh. I did not put it together that this was SSR. I'll look into that, but styled-components seems to not work with SSR per MUI's docs: https://mui.com/material-ui/guides/styled-engine/#how-to-switch-to-styled-components

Also the node_module aliases suggested in the https://vitejs.dev/guide/ssr.html#ssr-externals won't apply here as we're using npm.

I'll tinker some more and if I can't find another solution, seems like we'll just have to install @emotion/styled as a devDependency and call it a day for now.

Thank you for your assistance!