vitest: Vitest doesn't handle package.json `exports` conditions like `browser`

Describe the bug

We have a package that has a browser ESM & Node CJS & ESM builds. So exports looks something like this:

  "exports": {
    "types": "./dist/node.d.ts",
    "browser": "./dist/browser.mjs",
    "import": "./dist/node.mjs",
    "require": "./dist/node.js"
  },

Vitest selects the Node ESM build even with environment: "jsdom". Annoyingly, this can be a good thing for some packages, and bad for others in tests.

See https://jestjs.io/docs/29.0/configuration#testenvironmentoptions-object for the config and special comment syntax for this issue supported by Jest.

This might be difficult to support without loader hooks though Node does have a --conditions flag.

Reproduction

https://stackblitz.com/edit/vitest-dev-vitest-4jwegg?file=test/basic.test.ts

System Info

System:
    OS: macOS 12.6.2
    CPU: (10) arm64 Apple M1 Pro
    Memory: 123.48 MB / 16.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 16.19.0 - ~/.nvm/versions/node/v16.19.0/bin/node
    Yarn: 1.22.19 - ~/.nvm/versions/node/v16.19.0/bin/yarn
    npm: 9.2.0 - ~/.nvm/versions/node/v16.19.0/bin/npm
  Browsers:
    Chrome: 108.0.5359.124
    Safari: 16.2

Used Package Manager

npm

Validations

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 19 (17 by maintainers)

Most upvoted comments

Most of this stem from Node.js strict ESM support and the outright refusal of some tools to transpile code to work with it, without having to change it, e.g. TypeScript refusing to automatically add file extensions to imports. JSON imports requiring import assertions, but tools don’t add those and some don’t even support them in the code (e.g. in Vue SFC). And on and on.

Since we are using an opinionated tool (Vite) under the hood, we can make certain assumptions about the code we are running, so I am planning to explore ways to make it easier to load those dependencies in Node using VM API (it looks like the Node.js team is working on it in the latest Node versions, https://github.com/nodejs/node/pull/49932 doesn’t fix the issue but it’s a start) - there is already an option to transform those files in --experimental-vm-threads: https://vitest.dev/config/#deps-web-transformassets The main bottleneck right now is the performance - funny enough it takes longer to resolve imports than to transform code.

Alternatively, loaders API is already available but it’s too unstable (every minor Node.js release breaks it).

But even then I don’t think we will allow browser condition by default. Vue tests for example don’t even run because test-utils use UMD build which pollutes the global namespace instead of using ESM.

Browser condition usually has ESM that Node doesn’t support (like imports without .js extension or no type: "module"), so yes, Vitest doesn’t add it even with jsdom enabled, because it just won’t run in most cases.

You can enable browser condition (or any condition), using config:

export default {
  resolve: {
    conditions: ['browser']
  }
}

Vitest passes these conditions to Node with --conditions flag that you mentioned, and also uses this flag to resolve imports inside your source code with Vite.