Skip to content

Commit 9761f72

Browse files
committed
Exclude client environment from integration container plugin
Replace Vite's this.resolve() with Node's require.resolve() for resolving injected route entrypoints. The Vite resolve call triggers the client dep optimizer's registerMissingImport for server-only routes, which can race against optimizer init and produce a metadata cache missing React dependencies.
1 parent b6ee23d commit 9761f72

2 files changed

Lines changed: 26 additions & 14 deletions

File tree

.changeset/great-clocks-judge.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'astro': patch
3+
---
4+
5+
Fixes a race condition where the Vite dep optimizer could lose React dependencies in dev mode when using Astro Actions
Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import type { PluginContext } from 'rollup';
1+
import { createRequire } from 'node:module';
2+
import { fileURLToPath } from 'node:url';
23
import type { Plugin as VitePlugin } from 'vite';
34
import { normalizePath } from 'vite';
45
import type { AstroLogger } from '../core/logger/core.js';
@@ -20,25 +21,31 @@ export default function astroIntegrationsContainerPlugin({
2021
if (server.config.isProduction) return;
2122
await runHookServerSetup({ config: settings.config, server, logger });
2223
},
23-
async buildStart() {
24+
buildStart() {
2425
if (settings.injectedRoutes.length === settings.resolvedInjectedRoutes.length) return;
25-
// Ensure the injectedRoutes are all resolved to their final paths through Rollup
26-
settings.resolvedInjectedRoutes = await Promise.all(
27-
settings.injectedRoutes.map((route) => resolveEntryPoint.call(this, route)),
26+
// Resolve injected routes using Node resolution instead of Vite's this.resolve()
27+
// to avoid triggering the client dep optimizer's registerMissingImport, which can
28+
// race against optimizer init and corrupt the cache.
29+
const require = createRequire(settings.config.root);
30+
settings.resolvedInjectedRoutes = settings.injectedRoutes.map((route) =>
31+
resolveEntryPoint(route, settings.config.root, require),
2832
);
2933
},
3034
};
3135
}
3236

33-
async function resolveEntryPoint(
34-
this: PluginContext,
37+
function resolveEntryPoint(
3538
route: InternalInjectedRoute,
36-
): Promise<ResolvedInjectedRoute> {
37-
const resolvedId = await this.resolve(route.entrypoint.toString())
38-
.then((res) => res?.id)
39-
.catch(() => undefined);
40-
if (!resolvedId) return route;
41-
42-
const resolvedEntryPoint = new URL(`file://${normalizePath(resolvedId)}`);
39+
root: URL,
40+
require: NodeRequire,
41+
): ResolvedInjectedRoute {
42+
const entrypoint = route.entrypoint.toString();
43+
let resolved: string;
44+
try {
45+
resolved = require.resolve(entrypoint);
46+
} catch {
47+
resolved = fileURLToPath(new URL(entrypoint, root));
48+
}
49+
const resolvedEntryPoint = new URL(`file://${normalizePath(resolved)}`);
4350
return { ...route, resolvedEntryPoint };
4451
}

0 commit comments

Comments
 (0)