-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
in globalSetup, wrong module version served in pnpm workspaces #10028
Description
Describe the bug
When a pnpm workspace has multiple versions of the same dependency (e.g., @azure/core-lro@2.7.2 from a published npm package and @azure/core-lro@3.x from a workspace link), vitest serves the wrong version to some importers, causing:
SyntaxError: [vite] The requested module '@azure/core-lro' does not provide an export named 'deserializeState'
Root cause: The configEnvironment hook in vitest's VitestResolver plugin returns early for the __vitest__ environment (line: if (name === "__vitest_vm__" || name === "__vitest__") return;). This skips setting resolve.noExternal = true for the main test environment. Without this, Vite's import analysis plugin treats bare specifiers of node_modules packages as "external" and does not resolve them during transform, leaving raw bare specifiers in the transformed code.
This triggers a cascade of bugs:
- Vite's
createIsExternalcaches externalization decisions by bare specifier (theprocessedIdsmap), ignoring the importer. Once@azure/core-lrois deemed external for one importer, ALL importers get the same result. - Vite's module runner caches modules by URL (
urlToIdModuleMap). The bare specifier@azure/core-lromaps to whichever version was resolved first (2.7.2), and all subsequent importers get that cached module. - The
{ cache: true }protocol between client and server doesn't carry module identity. The server resolves the bare specifier to the correct version (3.x), sees it was already transformed, and returns{ cache: true }. The client interprets this as "use what you have" and serves the wrong version (2.7.2).
Workaround: Add resolve.dedupe: ["@azure/core-lro"] to vitest.config.ts. This forces Vite's import analysis to resolve the bare specifier from the project root, producing a consistent /@fs/... URL that bypasses all three cache issues.
Reproduction
https://github.com/Azure/azure-sdk-for-js
git clone https://github.com/Azure/azure-sdk-for-js.git
cd azure-sdk-for-js
git checkout cd25924f9c263e012f50a447a770ac68d703d2a4
pnpm install
cd sdk/batch/batch
npx vitest run --no-coverage test/files.spec.tsExpected: Tests pass (or fail for non-resolution reasons)
Actual: SyntaxError: The requested module '@azure/core-lro' does not provide an export named 'deserializeState'
Steps to reproduce
The dependency tree that triggers this:
@azure/batch(test target) depends on:@azure/arm-batch(workspace link) →@azure/core-lroworkspace (3.x, hasdeserializeState)@azure/arm-resources@5.2.0(published npm) →@azure/core-lro@2.7.2(nodeserializeState)
The arm-resources package uses ESM syntax without "type": "module" in package.json, so vitest's shouldExternalize returns false for its files — they're transformed by Vite. During transform, Vite's import analysis encounters import { ... } from "@azure/core-lro":
shouldExternalize(environment, "@azure/core-lro", "arm-resources/deployments.js")→ callscreateIsExternal→ resolves to 2.7.2 (in node_modules) →canExternalizeFile→ true → bare specifier NOT resolved → cached inprocessedIds["@azure/core-lro"] = trueshouldExternalize(environment, "@azure/core-lro", "arm-batch/pollingHelpers.js")→processedIds.has("@azure/core-lro")→ returns cachedtrue→ bare specifier NOT resolved (even though this importer should get 3.x)- Module runner receives
__vite_ssr_import__("@azure/core-lro")from both importers → first resolution (2.7.2) cached inurlToIdModuleMap["@azure/core-lro"]→ second importer gets stale 2.7.2 → crash
System Info
vitest/4.1.2 linux-x64 node-v22.22.1
vite/7.3.1
pnpm/10.33.0Used Package Manager
pnpm
Validations
- Follow our Code of Conduct
- Read the Contributing Guidelines.
- Read the docs.
- Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
- Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord Chat Server.
- The provided reproduction is a minimal reproducible example of the bug.