Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/vitest-ssr-no-browser-condition.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'vite-plugin-solid': patch
---

In jsdom and happy-dom tests, Node no longer gets the `browser` condition for packages that Vitest leaves external. Node-only packages such as `msw/node` now load under Vitest 4 and later (#125).
2 changes: 1 addition & 1 deletion examples/vite-6/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"preview": "vite preview",
"test": "vitest --browser.headless --run",
"test-dev": "vitest",
"test:jsdom": "NODE_OPTIONS=--import=./tests/deno-conditions.mjs vitest --run --config vitest.jsdom.config.ts --pool=forks"
"test:jsdom": "NODE_OPTIONS=--import=./tests/deno-conditions.mjs vitest --run --config vitest.jsdom.config.ts --pool=forks && node tests/node-conditions.mjs"
},
"devDependencies": {
"@solidjs/testing-library": "^0.8.10",
Expand Down
41 changes: 41 additions & 0 deletions examples/vite-6/tests/node-conditions.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Vitest passes the `ssr` environment's conditions to Node as `--conditions`
// for the packages it leaves external. In a jsdom test run the plugin used to
// add `browser` there, so Node-only packages failed to load. For example,
// `msw/node` imports `@mswjs/interceptors/ClientRequest`, whose `browser`
// export is `null` (#125).
//
// Checks:
// - jsdom: `client` keeps `browser`, `ssr` does not.
// - node environment: `ssr` keeps `browser`, since its tests run there.
import { resolveConfig } from 'vite';
import solid from 'vite-plugin-solid';

async function conditions(test) {
const resolved = await resolveConfig(
{ mode: 'test', configFile: false, logLevel: 'silent', plugins: [solid()], test },
'serve',
);
return {
client: resolved.environments.client.resolve.conditions,
ssr: resolved.environments.ssr.resolve.conditions,
};
}

const failures = [];
const jsdom = await conditions({ environment: 'jsdom' });
if (!jsdom.client.includes('browser')) {
failures.push(`jsdom: client conditions lack browser: ${JSON.stringify(jsdom.client)}`);
}
if (jsdom.ssr.includes('browser')) {
failures.push(`jsdom: ssr conditions include browser: ${JSON.stringify(jsdom.ssr)}`);
}
const node = await conditions({ environment: 'node' });
if (!node.ssr.includes('browser')) {
failures.push(`node: ssr conditions lack browser: ${JSON.stringify(node.ssr)}`);
}

if (failures.length) {
for (const failure of failures) console.error(`FAIL: ${failure}`);
process.exit(1);
}
console.log('PASS: jsdom tests keep browser out of the ssr conditions');
24 changes: 23 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@ export default function solidPlugin(options: Partial<Options> = {}): Plugin {
// by the crawl in test mode. They are inlined with solid-js (see
// `test.server.deps` below).
const testRuntimeConsumers = new Set<string>();
// True when a DOM test run inlines the Solid runtime. The `ssr`
// environment then does not get the `browser` condition (see
// `configEnvironment` below).
let domTestRuntimeInlined = false;

return {
name: 'solid',
Expand All @@ -228,6 +232,7 @@ export default function solidPlugin(options: Partial<Options> = {}): Plugin {
replaceDev = options.dev === true || (options.dev !== false && command === 'serve');
projectRoot = userConfig.root;
isTestMode = userConfig.mode === 'test';
domTestRuntimeInlined = false;

if (!userConfig.resolve) userConfig.resolve = {};
userConfig.resolve.alias = normalizeAliases(userConfig.resolve && userConfig.resolve.alias);
Expand Down Expand Up @@ -310,6 +315,11 @@ export default function solidPlugin(options: Partial<Options> = {}): Plugin {
},
};
}
const environment = userTest.environment ?? test.environment;
domTestRuntimeInlined =
!options.ssr &&
!userTest.browser?.enabled &&
(environment === 'jsdom' || environment === 'happy-dom');
}
if (!userTest.browser?.enabled) {
// vitest browser mode already has bundled jest-dom assertions
Expand Down Expand Up @@ -367,10 +377,22 @@ export default function solidPlugin(options: Partial<Options> = {}): Plugin {
config.resolve.conditions = [...defaultServerConditions];
}
}
// Vitest passes the `ssr` environment's conditions to Node as
// `--conditions` for the packages it leaves external. With `browser`
// there, Node-only packages fail to load. For example, `msw/node`
// imports `@mswjs/interceptors/ClientRequest`, whose `browser`
// export is `null` (#125). DOM tests run in the `client` environment,
// and the Solid runtime is inlined in that case, so the `ssr`
// environment does not need `browser`.
const addBrowser =
isTestMode &&
!opts.isSsrTargetWebworker &&
!options.ssr &&
!(domTestRuntimeInlined && name === 'ssr');
config.resolve.conditions = [
'solid',
...(replaceDev ? ['development'] : []),
...(isTestMode && !opts.isSsrTargetWebworker && !options.ssr ? ['browser'] : []),
...(addBrowser ? ['browser'] : []),
...config.resolve.conditions,
];

Expand Down
Loading