Skip to content

Commit 20afb6f

Browse files
fix: pre-bundle devtools when it is only a dependency of the plugin
The optimizeDeps include for @solidjs/start-devtools was gated on the package being reachable from the app root, but resolveDevtools happily falls back to resolving it from the plugin's own location — so in pnpm-isolated installs the toolbar was enabled without being pre-bundled. It enters the graph behind virtual modules the scanner never crawls, and the resulting first-request re-optimize can pair chunks from different passes whose shared minified exports disagree, taking down the whole client entry graph. Emit Vite's nested-include form (`@solidjs/vite-plugin > @solidjs/start-devtools`) for that install shape so enablement and pre-bundling can't disagree. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent dc52da8 commit 20afb6f

1 file changed

Lines changed: 28 additions & 8 deletions

File tree

src/ssr/index.ts

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -506,14 +506,13 @@ export function startServe(
506506
}
507507

508508
/**
509-
* Cheap root-walk probe mirroring how the optimizer resolves bare
509+
* Cheap walk-up probe mirroring how the optimizer resolves bare
510510
* `optimizeDeps.include` entries: is @solidjs/start-devtools reachable from
511-
* the Vite root? Detection proper (resolveDevtools) runs later with a real
511+
* this directory? Detection proper (resolveDevtools) runs later with a real
512512
* importer; this only decides whether the toolbar graph can be pre-bundled
513-
* at scan time — it hangs off virtual modules the scanner never sees, so
514-
* first-request discovery would force a re-optimize + full page reload.
513+
* at scan time.
515514
*/
516-
function devtoolsReachableFromRoot(dir: string): boolean {
515+
function devtoolsReachableFrom(dir: string): boolean {
517516
for (let current = dir; ; ) {
518517
if (existsSync(path.join(current, 'node_modules', DEVTOOLS_PACKAGE, 'package.json'))) {
519518
return true;
@@ -524,6 +523,26 @@ export function startServe(
524523
}
525524
}
526525

526+
/**
527+
* The `optimizeDeps.include` spec that pre-bundles the toolbar graph, or
528+
* null when it cannot be resolved at all. Pre-bundling it is not just a
529+
* warm-start nicety: the toolbar hangs off virtual modules the scanner
530+
* never crawls, so without an include the optimizer only discovers it on
531+
* first request. That re-optimize can pair chunks from different passes
532+
* whose shared minified exports disagree, taking down the whole client
533+
* entry graph. The spec must therefore cover every install shape
534+
* resolveDevtools accepts: bare when the app installs the package, and
535+
* Vite's nested-include form (`plugin > dep`) when it is only a dependency
536+
* of this plugin (pnpm-isolated installs).
537+
*/
538+
function devtoolsIncludeSpec(rootDir: string): string | null {
539+
if (devtoolsReachableFrom(rootDir)) return DEVTOOLS_PACKAGE;
540+
if (devtoolsReachableFrom(path.dirname(fileURLToPath(import.meta.url)))) {
541+
return `@solidjs/vite-plugin > ${DEVTOOLS_PACKAGE}`;
542+
}
543+
return null;
544+
}
545+
527546
/** Import specifier for generated code: absolute for files, id for virtuals. */
528547
function entryServerSpec(): string {
529548
const { entryServer } = requireEntries();
@@ -1196,9 +1215,10 @@ export function startServe(
11961215
// Like the refresh runtime in the main plugin: the toolbar
11971216
// graph is injected behind modules the scanner never crawls,
11981217
// so pre-bundle it and the server-functions runtime up front.
1199-
...(devtoolsEnabled && devtoolsReachableFromRoot(root)
1200-
? { include: [DEVTOOLS_PACKAGE, '@solidjs/web/server-functions'] }
1201-
: {}),
1218+
...(() => {
1219+
const spec = devtoolsEnabled ? devtoolsIncludeSpec(root) : null;
1220+
return spec ? { include: [spec, '@solidjs/web/server-functions'] } : {};
1221+
})(),
12021222
},
12031223
}),
12041224
};

0 commit comments

Comments
 (0)