From dd217612f8e777745ab7320e17844309500bccb8 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 21 Oct 2026 10:14:06 +0000 Subject: [PATCH] fix: pre-bundle @solidjs/signals when the app depends on it directly Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_016PFhdmTPKsQSS3fENqTi5b --- .changeset/signals-optimize-include.md | 12 ++++++++++++ src/index.ts | 14 ++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 .changeset/signals-optimize-include.md diff --git a/.changeset/signals-optimize-include.md b/.changeset/signals-optimize-include.md new file mode 100644 index 0000000..66830a0 --- /dev/null +++ b/.changeset/signals-optimize-include.md @@ -0,0 +1,12 @@ +--- +'@solidjs/vite-plugin': patch +--- + +Pre-bundle `@solidjs/signals` up front under `vite dev` (and Vitest browser +mode) when the app can import it by name, i.e. it resolves from the project +root. The first optimizer pass otherwise inlines signals into `solid-js`, so a +direct `@solidjs/signals` import from a module the scanner never reached (a +browser-mode test file, a non-literal dynamic import) was a late discovery: +re-optimize and a full page reload ("Vite unexpectedly reloaded a test"). +Apps that only get signals transitively (pnpm's isolated layout) are +unchanged. diff --git a/src/index.ts b/src/index.ts index 07b31e0..a16591a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1531,10 +1531,7 @@ export default function solidPlugin(options: Partial = {}): Plugin[] { // `solid-js` fails with ERR_MODULE_NOT_FOUND as soon as anything // externalizes it (vitefu does, once a semi-framework package such as // `@solidjs/diagnostics` lists it under `dependencies`). With no root - // copy there is nothing to dedupe TO, so the gate loses nothing. Not - // added to `optimizeDeps.include`: the optimizer already reaches - // signals through `solid-js`, and an include entry that doesn't - // resolve from the root logs a warning on every start. + // copy there is nothing to dedupe TO, so the gate loses nothing. // // Dedupe applies to builds as well as dev. A dependency that ships its // own nested copy of `solid-js` would otherwise put a second runtime @@ -1545,6 +1542,7 @@ export default function solidPlugin(options: Partial = {}): Plugin[] { const dedupe = ['solid-js', '@solidjs/web', '@solidjs/signals'].filter((name) => findPackageDir(name, dedupeRoot), ); + const rootSignals = dedupe.includes('@solidjs/signals'); const userTest = (userConfig as any).test ?? {}; const test = {} as any; @@ -1709,6 +1707,14 @@ export default function solidPlugin(options: Partial = {}): Plugin[] { ...(command === 'serve' ? ['solid-js/attribution', '@solidjs/web/performance-tracks'] : []), + // An app that depends on `@solidjs/signals` directly can import + // it from a module the scanner never reaches (a test file in + // Vitest browser mode, a non-literal dynamic import). The first + // pass bundled signals inside `solid-js`, so that import is a + // late discovery: re-optimize, full reload. Only when it resolves + // from the root: otherwise the app can't import it by name, and + // an include entry that doesn't resolve warns on every start. + ...(command === 'serve' && rootSignals ? ['@solidjs/signals'] : []), ...solidPkgsConfig.optimizeDeps.include, ], exclude: solidPkgsConfig.optimizeDeps.exclude,