diff --git a/packages/vinext/src/index.ts b/packages/vinext/src/index.ts index 347d7d6775..ce4a9e54fd 100644 --- a/packages/vinext/src/index.ts +++ b/packages/vinext/src/index.ts @@ -1960,6 +1960,12 @@ hydrate(); "react/jsx-dev-runtime", ], }, + // Exclude vinext from dependency optimization so esbuild doesn't + // scan dist files containing virtual module imports (virtual:vinext-*) + // that only resolve at Vite plugin time, not during pre-bundling. + optimizeDeps: { + exclude: ["vinext"], + }, // Enable JSX in .tsx/.jsx files // Vite 7 uses `esbuild` for transforms, Vite 8+ uses `oxc` ...(getViteMajorVersion() >= 8 @@ -2004,6 +2010,7 @@ hydrate(); }, }), optimizeDeps: { + exclude: ["vinext"], entries: appEntries, }, build: { @@ -2015,6 +2022,7 @@ hydrate(); }, ssr: { optimizeDeps: { + exclude: ["vinext"], entries: appEntries, }, build: { @@ -2026,6 +2034,7 @@ hydrate(); }, client: { optimizeDeps: { + exclude: ["vinext"], // react and react-dom are framework dependencies used for // hydration. They aren't crawled from app/ source files so // must be pre-included to prevent late discovery and page diff --git a/tests/build-optimization.test.ts b/tests/build-optimization.test.ts index 1c41cc378a..0968f2016d 100644 --- a/tests/build-optimization.test.ts +++ b/tests/build-optimization.test.ts @@ -65,6 +65,93 @@ describe("clientManualChunks", () => { }); }); +// ─── optimizeDeps.exclude — prevents esbuild scanning virtual module imports ─ + +describe("optimizeDeps.exclude for vinext", () => { + it("excludes vinext at top level for Pages Router builds", async () => { + const vinext = (await import("../packages/vinext/src/index.js")).default; + const plugins = vinext(); + + const mainPlugin = plugins.find( + (p: any) => p.name === "vinext:config" && typeof p.config === "function", + ); + expect(mainPlugin).toBeDefined(); + + const os = await import("node:os"); + const fsp = await import("node:fs/promises"); + const path = await import("node:path"); + + const tmpDir = await fsp.mkdtemp(path.join(os.tmpdir(), "vinext-ts-test-optdeps-")); + const rootNodeModules = path.resolve(import.meta.dirname, "../node_modules"); + await fsp.symlink(rootNodeModules, path.join(tmpDir, "node_modules"), "junction"); + + await fsp.mkdir(path.join(tmpDir, "pages"), { recursive: true }); + await fsp.writeFile( + path.join(tmpDir, "pages", "index.tsx"), + `export default function Home() { return