@reckona/mreact-router 0.0.81 → 0.0.83
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/adapters/aws-lambda.d.ts.map +1 -1
- package/dist/adapters/aws-lambda.js +17 -22
- package/dist/adapters/aws-lambda.js.map +1 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +3 -1
- package/dist/build.js.map +1 -1
- package/dist/client-route-inference.d.ts +2 -0
- package/dist/client-route-inference.d.ts.map +1 -0
- package/dist/client-route-inference.js +2 -0
- package/dist/client-route-inference.js.map +1 -0
- package/dist/client.d.ts +2 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +89 -24
- package/dist/client.js.map +1 -1
- package/dist/layout-composer.d.ts +24 -0
- package/dist/layout-composer.d.ts.map +1 -0
- package/dist/layout-composer.js +83 -0
- package/dist/layout-composer.js.map +1 -0
- package/dist/metadata.d.ts +9 -0
- package/dist/metadata.d.ts.map +1 -0
- package/dist/metadata.js +419 -0
- package/dist/metadata.js.map +1 -0
- package/dist/middleware.d.ts +22 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +94 -0
- package/dist/middleware.js.map +1 -0
- package/dist/module-runner.d.ts +2 -2
- package/dist/module-runner.d.ts.map +1 -1
- package/dist/module-runner.js +1 -1
- package/dist/module-runner.js.map +1 -1
- package/dist/navigation-runtime.d.ts +2 -0
- package/dist/navigation-runtime.d.ts.map +1 -0
- package/dist/navigation-runtime.js +2 -0
- package/dist/navigation-runtime.js.map +1 -0
- package/dist/preload-policy.d.ts +24 -0
- package/dist/preload-policy.d.ts.map +1 -0
- package/dist/preload-policy.js +45 -0
- package/dist/preload-policy.js.map +1 -0
- package/dist/render.d.ts +1 -3
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +32 -676
- package/dist/render.js.map +1 -1
- package/dist/route-hydration-contract.d.ts +11 -0
- package/dist/route-hydration-contract.d.ts.map +1 -0
- package/dist/route-hydration-contract.js +21 -0
- package/dist/route-hydration-contract.js.map +1 -0
- package/dist/route-module-loader.d.ts +10 -0
- package/dist/route-module-loader.d.ts.map +1 -0
- package/dist/route-module-loader.js +61 -0
- package/dist/route-module-loader.js.map +1 -0
- package/dist/routes.js +6 -0
- package/dist/routes.js.map +1 -1
- package/dist/serve.d.ts +13 -0
- package/dist/serve.d.ts.map +1 -1
- package/dist/serve.js +63 -28
- package/dist/serve.js.map +1 -1
- package/dist/server-action-inference.d.ts.map +1 -1
- package/dist/server-action-inference.js +37 -1
- package/dist/server-action-inference.js.map +1 -1
- package/dist/vite.d.ts.map +1 -1
- package/dist/vite.js +2 -1
- package/dist/vite.js.map +1 -1
- package/package.json +11 -11
- package/src/adapters/aws-lambda.ts +21 -28
- package/src/build.ts +9 -6
- package/src/client-route-inference.ts +18 -0
- package/src/client.ts +124 -24
- package/src/layout-composer.ts +142 -0
- package/src/metadata.ts +578 -0
- package/src/middleware.ts +153 -0
- package/src/module-runner.ts +3 -2
- package/src/navigation-runtime.ts +16 -0
- package/src/preload-policy.ts +89 -0
- package/src/render.ts +75 -986
- package/src/route-hydration-contract.ts +22 -0
- package/src/route-module-loader.ts +95 -0
- package/src/routes.ts +8 -0
- package/src/serve.ts +110 -29
- package/src/server-action-inference.ts +49 -0
- package/src/vite.ts +6 -4
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const routeHydrationContract = {
|
|
2
|
+
clientReferencesScriptPrefix: "mreact-client-references-",
|
|
3
|
+
hydratedAttribute: "data-mreact-hydrated",
|
|
4
|
+
hotRouteHydrateExport: "__mreactHotHydrateRoute",
|
|
5
|
+
propsScriptPrefix: "mreact-props-",
|
|
6
|
+
routeHydrateExport: "__mreactHydrateRoute",
|
|
7
|
+
routeMarkerAttribute: "data-mreact-route-id",
|
|
8
|
+
} as const;
|
|
9
|
+
|
|
10
|
+
export function routeDataScriptIds(routeId: string): [string, string] {
|
|
11
|
+
return [
|
|
12
|
+
`${routeHydrationContract.propsScriptPrefix}${routeId}`,
|
|
13
|
+
`${routeHydrationContract.clientReferencesScriptPrefix}${routeId}`,
|
|
14
|
+
];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function routeDataScriptSelector(): string {
|
|
18
|
+
return [
|
|
19
|
+
`script[type="application/json"][id^="${routeHydrationContract.propsScriptPrefix}"]`,
|
|
20
|
+
`script[type="application/json"][id^="${routeHydrationContract.clientReferencesScriptPrefix}"]`,
|
|
21
|
+
].join(", ");
|
|
22
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import type { BuiltServerModuleArtifact } from "./build.js";
|
|
3
|
+
import type { AppRouterImportPolicy } from "./import-policy.js";
|
|
4
|
+
|
|
5
|
+
export type BuiltServerModuleOutputLike = NonNullable<BuiltServerModuleArtifact["request"]>;
|
|
6
|
+
|
|
7
|
+
// Per-request hashText (SHA-256) is one of the hot path's dominant
|
|
8
|
+
// costs. Cache hashes for `code` strings we have already seen this
|
|
9
|
+
// process (common case: the prepared code is identical across requests
|
|
10
|
+
// when the source file is unchanged).
|
|
11
|
+
const codeHashCache = new Map<string, string>();
|
|
12
|
+
const MAX_CODE_HASH_ENTRIES = 256;
|
|
13
|
+
|
|
14
|
+
export function memoizedHashText(code: string): string {
|
|
15
|
+
const cached = codeHashCache.get(code);
|
|
16
|
+
if (cached !== undefined) {
|
|
17
|
+
return cached;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const hash = hashText(code);
|
|
21
|
+
if (codeHashCache.size >= MAX_CODE_HASH_ENTRIES) {
|
|
22
|
+
// Simple LRU eviction: drop the oldest entry (Map keeps insertion order).
|
|
23
|
+
const oldestKey = codeHashCache.keys().next().value;
|
|
24
|
+
if (oldestKey !== undefined) {
|
|
25
|
+
codeHashCache.delete(oldestKey);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
codeHashCache.set(code, hash);
|
|
29
|
+
return hash;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function prebuiltRequestModuleArtifact(
|
|
33
|
+
serverModules: ReadonlyMap<string, BuiltServerModuleArtifact> | undefined,
|
|
34
|
+
file: string,
|
|
35
|
+
source: string,
|
|
36
|
+
kind: "request" | "routeMetadata" = "request",
|
|
37
|
+
): BuiltServerModuleOutputLike | undefined {
|
|
38
|
+
const artifact = serverModules?.get(file)?.[kind];
|
|
39
|
+
|
|
40
|
+
return artifact !== undefined && artifact.sourceHash === memoizedHashText(source)
|
|
41
|
+
? artifact
|
|
42
|
+
: undefined;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function prebuiltRouteLoaderModuleArtifact(
|
|
46
|
+
serverModules: ReadonlyMap<string, BuiltServerModuleArtifact> | undefined,
|
|
47
|
+
file: string,
|
|
48
|
+
source: string,
|
|
49
|
+
): BuiltServerModuleOutputLike | undefined {
|
|
50
|
+
const artifact = serverModules?.get(file)?.loader;
|
|
51
|
+
|
|
52
|
+
return artifact !== undefined && artifact.sourceHash === memoizedHashText(source)
|
|
53
|
+
? artifact
|
|
54
|
+
: prebuiltRequestModuleArtifact(serverModules, file, source);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function prebuiltServerComponentModuleCode(
|
|
58
|
+
artifact: BuiltServerModuleArtifact["string"] | BuiltServerModuleArtifact["stream"] | undefined,
|
|
59
|
+
code: string,
|
|
60
|
+
codeHash: string,
|
|
61
|
+
): string | undefined {
|
|
62
|
+
if (artifact === undefined) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!prebuiltServerModuleOutputMatches(artifact, code, codeHash)) {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return artifact.bundleCode;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function prebuiltServerModuleOutputMatches(
|
|
74
|
+
artifact: BuiltServerModuleOutputLike,
|
|
75
|
+
code: string,
|
|
76
|
+
codeHash: string,
|
|
77
|
+
): boolean {
|
|
78
|
+
return artifact.sourceHash === codeHash || artifact.code === code;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function importPolicyCacheKey(policy: AppRouterImportPolicy | undefined): string {
|
|
82
|
+
if (policy === undefined) {
|
|
83
|
+
return "";
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return JSON.stringify({
|
|
87
|
+
allowedPackages: [...(policy.allowedPackages ?? [])].sort(),
|
|
88
|
+
allowedSourceDirs: [...(policy.allowedSourceDirs ?? [])].sort(),
|
|
89
|
+
projectRoot: policy.projectRoot ?? "",
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function hashText(text: string): string {
|
|
94
|
+
return createHash("sha256").update(text).digest("hex").slice(0, 16);
|
|
95
|
+
}
|
package/src/routes.ts
CHANGED
|
@@ -239,6 +239,10 @@ async function collectRouteFiles(directory: string, rootDirectory = directory):
|
|
|
239
239
|
const path = join(directory, entry.name);
|
|
240
240
|
|
|
241
241
|
if (entry.isDirectory()) {
|
|
242
|
+
if (shouldSkipRouteScanDirectory(entry.name)) {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
|
|
242
246
|
files.push(...(await collectRouteFiles(path, rootDirectory)));
|
|
243
247
|
continue;
|
|
244
248
|
}
|
|
@@ -257,6 +261,10 @@ async function collectRouteFiles(directory: string, rootDirectory = directory):
|
|
|
257
261
|
return files;
|
|
258
262
|
}
|
|
259
263
|
|
|
264
|
+
function shouldSkipRouteScanDirectory(name: string): boolean {
|
|
265
|
+
return name === ".vite" || name === "node_modules";
|
|
266
|
+
}
|
|
267
|
+
|
|
260
268
|
function appFileConventionForRelativeFile(
|
|
261
269
|
relativeFile: string,
|
|
262
270
|
): ReturnType<typeof appFileConventionForRootFilename> {
|
package/src/serve.ts
CHANGED
|
@@ -8,7 +8,7 @@ import type {
|
|
|
8
8
|
BuiltServerModuleArtifact,
|
|
9
9
|
} from "./build.js";
|
|
10
10
|
import type { AppRouterCache } from "./cache.js";
|
|
11
|
-
import type { ClientRouteManifestEntry } from "./client.js";
|
|
11
|
+
import type { ClientRouteManifestEntry } from "./client-route-inference.js";
|
|
12
12
|
import { createRouteMatcher, type AppRoute, type RouteMatcher } from "./routes.js";
|
|
13
13
|
import type { AppRouterServerActionOptions } from "./actions.js";
|
|
14
14
|
import type { AppRouterImportPolicy } from "./import-policy.js";
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
requestLogFields,
|
|
32
32
|
type AppRouterLogger,
|
|
33
33
|
} from "./logger.js";
|
|
34
|
+
import { builtAppRuntimePreloadPlan } from "./preload-policy.js";
|
|
34
35
|
import { routeShellCandidates } from "./route-shells.js";
|
|
35
36
|
import { normalizeRoutePath } from "./route-path.js";
|
|
36
37
|
import type { HttpUpgradeHandler } from "./upgrade.js";
|
|
@@ -116,11 +117,32 @@ export interface RenderBuiltAppRequestOptions {
|
|
|
116
117
|
request: Request;
|
|
117
118
|
routeCache?: AppRouterCache | undefined;
|
|
118
119
|
runtimeDir?: string | undefined;
|
|
120
|
+
immutableRuntime?: boolean | undefined;
|
|
119
121
|
serverActions?: AppRouterServerActionOptions | undefined;
|
|
120
122
|
sinkStrategy?: ResponseSinkStrategy;
|
|
121
123
|
preload?: AppRouterRenderPreload | undefined;
|
|
122
124
|
}
|
|
123
125
|
|
|
126
|
+
export interface BuiltRequestRuntimeOptions {
|
|
127
|
+
immutableRuntime?: boolean | undefined;
|
|
128
|
+
importPolicy?: AppRouterImportPolicy | undefined;
|
|
129
|
+
outDir: string;
|
|
130
|
+
runtimeDir?: string | undefined;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export type BuiltRequestRuntimeRenderOptions = Omit<
|
|
134
|
+
RenderBuiltAppRequestOptions,
|
|
135
|
+
"immutableRuntime" | "outDir" | "request" | "runtimeDir"
|
|
136
|
+
>;
|
|
137
|
+
|
|
138
|
+
export interface BuiltRequestRuntime {
|
|
139
|
+
preload(preload?: BuiltAppRuntimePreloadStrategy | undefined): Promise<void>;
|
|
140
|
+
render(
|
|
141
|
+
request: Request,
|
|
142
|
+
options?: BuiltRequestRuntimeRenderOptions | undefined,
|
|
143
|
+
): Promise<Response>;
|
|
144
|
+
}
|
|
145
|
+
|
|
124
146
|
export type BuiltAppRuntimePreloadMode =
|
|
125
147
|
| "all"
|
|
126
148
|
| "hot-route-requests"
|
|
@@ -201,6 +223,40 @@ export interface AppRouterPrerenderStore {
|
|
|
201
223
|
withLock?<T>(path: string, task: () => Promise<T>): Promise<T>;
|
|
202
224
|
}
|
|
203
225
|
|
|
226
|
+
export async function createBuiltRequestRuntime(
|
|
227
|
+
options: BuiltRequestRuntimeOptions,
|
|
228
|
+
): Promise<BuiltRequestRuntime> {
|
|
229
|
+
const runtime = await readBuiltRuntime({
|
|
230
|
+
immutable: options.immutableRuntime,
|
|
231
|
+
outDir: options.outDir,
|
|
232
|
+
runtimeDir: options.runtimeDir,
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
return {
|
|
236
|
+
preload(preload) {
|
|
237
|
+
return preloadBuiltAppRuntimeWithRuntime({
|
|
238
|
+
importPolicy: options.importPolicy,
|
|
239
|
+
preload,
|
|
240
|
+
runtime,
|
|
241
|
+
});
|
|
242
|
+
},
|
|
243
|
+
async render(request, renderOptions = {}) {
|
|
244
|
+
const response = await renderBuiltAppRequestWithRuntime({
|
|
245
|
+
...renderOptions,
|
|
246
|
+
importPolicy: renderOptions.importPolicy ?? options.importPolicy,
|
|
247
|
+
outDir: options.outDir,
|
|
248
|
+
request,
|
|
249
|
+
runtime,
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
return applyBuiltAppResponseHook(response, {
|
|
253
|
+
onResponse: renderOptions.onResponse,
|
|
254
|
+
request,
|
|
255
|
+
});
|
|
256
|
+
},
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
204
260
|
export async function preloadBuiltAppRuntime(options: {
|
|
205
261
|
importPolicy?: AppRouterImportPolicy | undefined;
|
|
206
262
|
outDir: string;
|
|
@@ -211,38 +267,57 @@ export async function preloadBuiltAppRuntime(options: {
|
|
|
211
267
|
outDir: options.outDir,
|
|
212
268
|
runtimeDir: options.runtimeDir,
|
|
213
269
|
});
|
|
214
|
-
|
|
270
|
+
await preloadBuiltAppRuntimeWithRuntime({
|
|
271
|
+
importPolicy: options.importPolicy,
|
|
272
|
+
preload: options.preload,
|
|
273
|
+
runtime,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
215
276
|
|
|
216
|
-
|
|
277
|
+
async function preloadBuiltAppRuntimeWithRuntime(options: {
|
|
278
|
+
importPolicy?: AppRouterImportPolicy | undefined;
|
|
279
|
+
preload?: BuiltAppRuntimePreloadStrategy | undefined;
|
|
280
|
+
runtime: BuiltRuntime;
|
|
281
|
+
}): Promise<void> {
|
|
282
|
+
const plan = builtAppRuntimePreloadPlan(options.preload);
|
|
283
|
+
|
|
284
|
+
if (!plan.shouldPreload) {
|
|
217
285
|
return;
|
|
218
286
|
}
|
|
219
287
|
|
|
220
|
-
const routes = builtRuntimePreloadRoutes(runtime,
|
|
221
|
-
if (
|
|
222
|
-
await loadBuiltServerModuleArtifacts(
|
|
288
|
+
const routes = builtRuntimePreloadRoutes(options.runtime, plan);
|
|
289
|
+
if (plan.loadAllArtifacts) {
|
|
290
|
+
await loadBuiltServerModuleArtifacts(
|
|
291
|
+
options.runtime,
|
|
292
|
+
allBuiltServerModuleFiles(options.runtime),
|
|
293
|
+
"all",
|
|
294
|
+
);
|
|
223
295
|
} else {
|
|
224
|
-
await loadBuiltServerModuleArtifactsForRequest(
|
|
225
|
-
|
|
226
|
-
|
|
296
|
+
await loadBuiltServerModuleArtifactsForRequest(
|
|
297
|
+
options.runtime,
|
|
298
|
+
undefined,
|
|
299
|
+
plan.middlewareArtifacts,
|
|
300
|
+
);
|
|
227
301
|
for (const route of routes) {
|
|
228
|
-
await loadBuiltServerModuleArtifactsForRequest(
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
302
|
+
await loadBuiltServerModuleArtifactsForRequest(
|
|
303
|
+
options.runtime,
|
|
304
|
+
route.file,
|
|
305
|
+
plan.routeArtifacts,
|
|
306
|
+
);
|
|
232
307
|
}
|
|
233
308
|
}
|
|
234
309
|
await preloadBuiltRequestModules({
|
|
235
|
-
appDir: runtime.appDir,
|
|
310
|
+
appDir: options.runtime.appDir,
|
|
236
311
|
importPolicy: {
|
|
237
312
|
...options.importPolicy,
|
|
238
|
-
allowedSourceDirs: runtime.allowedSourceDirs,
|
|
239
|
-
projectRoot: runtime.projectRoot,
|
|
313
|
+
allowedSourceDirs: options.runtime.allowedSourceDirs,
|
|
314
|
+
projectRoot: options.runtime.projectRoot,
|
|
240
315
|
},
|
|
241
316
|
routes,
|
|
242
|
-
serverModules: runtime.serverModules,
|
|
243
|
-
serverModuleCacheVersion: runtime.serverModuleCacheVersion,
|
|
244
|
-
serverSourceFiles: runtime.serverSourceFiles,
|
|
245
|
-
includeRenderModules:
|
|
317
|
+
serverModules: options.runtime.serverModules,
|
|
318
|
+
serverModuleCacheVersion: options.runtime.serverModuleCacheVersion,
|
|
319
|
+
serverSourceFiles: options.runtime.serverSourceFiles,
|
|
320
|
+
includeRenderModules: plan.includeRenderModules,
|
|
246
321
|
});
|
|
247
322
|
}
|
|
248
323
|
|
|
@@ -275,6 +350,7 @@ export async function renderBuiltAppRequest(
|
|
|
275
350
|
...options,
|
|
276
351
|
runtime: await readBuiltRuntime({
|
|
277
352
|
outDir: options.outDir,
|
|
353
|
+
immutable: options.immutableRuntime,
|
|
278
354
|
runtimeDir: options.runtimeDir,
|
|
279
355
|
}),
|
|
280
356
|
});
|
|
@@ -470,7 +546,10 @@ export async function startServer(
|
|
|
470
546
|
options: StartServerOptions,
|
|
471
547
|
): Promise<{ close(): Promise<void>; server: Server; url: string }> {
|
|
472
548
|
warnIfImplicitHostTrust(options);
|
|
473
|
-
const runtime = await
|
|
549
|
+
const runtime = await createBuiltRequestRuntime({
|
|
550
|
+
importPolicy: options.importPolicy,
|
|
551
|
+
outDir: options.outDir,
|
|
552
|
+
});
|
|
474
553
|
const server = createServer(async (incoming, outgoing) => {
|
|
475
554
|
const startedAt = logNow();
|
|
476
555
|
const fallbackRequestFields = {
|
|
@@ -494,19 +573,15 @@ export async function startServer(
|
|
|
494
573
|
...logFields,
|
|
495
574
|
type: "router:request:start",
|
|
496
575
|
});
|
|
497
|
-
const response = await
|
|
498
|
-
outDir: options.outDir,
|
|
499
|
-
importPolicy: options.importPolicy,
|
|
576
|
+
const response = await runtime.render(request, {
|
|
500
577
|
instrumentation: options.instrumentation,
|
|
501
578
|
logger: options.logger,
|
|
502
579
|
onResponse: options.onResponse,
|
|
503
580
|
prerenderStore: options.prerenderStore,
|
|
504
|
-
request,
|
|
505
581
|
routeCache: options.routeCache,
|
|
506
|
-
runtime,
|
|
507
582
|
serverActions: options.serverActions,
|
|
508
583
|
...(options.sinkStrategy === undefined ? {} : { sinkStrategy: options.sinkStrategy }),
|
|
509
|
-
})
|
|
584
|
+
});
|
|
510
585
|
emitRouterLog(options.logger, "info", {
|
|
511
586
|
...logFields,
|
|
512
587
|
durationMs: logDurationMs(startedAt),
|
|
@@ -632,17 +707,23 @@ async function readBuiltPublicAsset(
|
|
|
632
707
|
}
|
|
633
708
|
|
|
634
709
|
async function readBuiltRuntime(options: {
|
|
710
|
+
immutable?: boolean | undefined;
|
|
635
711
|
outDir: string;
|
|
636
712
|
runtimeDir?: string | undefined;
|
|
637
713
|
}): Promise<BuiltRuntime> {
|
|
638
714
|
const outDir = options.outDir;
|
|
639
715
|
const runtimeDir = options.runtimeDir ?? join(outDir, "server", "runtime");
|
|
716
|
+
const cacheKey = `${outDir}\0${runtimeDir}`;
|
|
717
|
+
const cached = builtRuntimeCache.get(cacheKey);
|
|
718
|
+
|
|
719
|
+
if (options.immutable === true && cached !== undefined) {
|
|
720
|
+
return cached.runtime;
|
|
721
|
+
}
|
|
722
|
+
|
|
640
723
|
const [serverManifestText, clientManifestText] = await Promise.all([
|
|
641
724
|
readFile(join(outDir, "server", "manifest.json"), "utf8"),
|
|
642
725
|
readFile(join(outDir, "client", "manifest.json"), "utf8"),
|
|
643
726
|
]);
|
|
644
|
-
const cacheKey = `${outDir}\0${runtimeDir}`;
|
|
645
|
-
const cached = builtRuntimeCache.get(cacheKey);
|
|
646
727
|
|
|
647
728
|
if (
|
|
648
729
|
cached !== undefined &&
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { dirname, relative, sep } from "node:path";
|
|
3
3
|
import {
|
|
4
|
+
analyzeBoundaryGraph,
|
|
4
5
|
collectFormActionExpressionReferences,
|
|
5
6
|
hasModuleDirective,
|
|
6
7
|
type FormActionExpressionReference,
|
|
@@ -154,6 +155,14 @@ export async function collectBuildInferredServerActions(options: {
|
|
|
154
155
|
const diagnostics: ServerActionInferenceDiagnostic[] = [];
|
|
155
156
|
const references: InferredServerActionExpressionReference[] = [];
|
|
156
157
|
const sourceHash = formActionSourceHash(options.source);
|
|
158
|
+
const graphReferences = await collectBuildBoundaryGraphServerActions({
|
|
159
|
+
file: options.file,
|
|
160
|
+
files: options.files,
|
|
161
|
+
relativeRoutesDir: options.relativeRoutesDir,
|
|
162
|
+
resolveSourceImport: options.resolveSourceImport,
|
|
163
|
+
source: options.source,
|
|
164
|
+
sourceHash,
|
|
165
|
+
});
|
|
157
166
|
|
|
158
167
|
for (const formReference of formReferences) {
|
|
159
168
|
const expression = findExpressionAt(sourceFile, formReference);
|
|
@@ -185,6 +194,13 @@ export async function collectBuildInferredServerActions(options: {
|
|
|
185
194
|
continue;
|
|
186
195
|
}
|
|
187
196
|
|
|
197
|
+
const graphReference = graphReferences.get(formActionOccurrenceKey(formReference));
|
|
198
|
+
|
|
199
|
+
if (graphReference !== undefined) {
|
|
200
|
+
references.push(graphReference);
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
|
|
188
204
|
if (resolved.kind === "dynamic") {
|
|
189
205
|
diagnostics.push({
|
|
190
206
|
code: dynamicFormActionInferenceCode,
|
|
@@ -198,6 +214,39 @@ export async function collectBuildInferredServerActions(options: {
|
|
|
198
214
|
return { diagnostics, references };
|
|
199
215
|
}
|
|
200
216
|
|
|
217
|
+
async function collectBuildBoundaryGraphServerActions(options: {
|
|
218
|
+
file: string;
|
|
219
|
+
files: Record<string, string>;
|
|
220
|
+
relativeRoutesDir: string;
|
|
221
|
+
resolveSourceImport: (importer: string, source: string) => string | undefined;
|
|
222
|
+
source: string;
|
|
223
|
+
sourceHash: string;
|
|
224
|
+
}): Promise<Map<string, InferredServerActionExpressionReference>> {
|
|
225
|
+
const graph = await analyzeBoundaryGraph({
|
|
226
|
+
entries: [{ file: options.file, kind: "route-page" }],
|
|
227
|
+
readModule: (file) => (file === options.file ? options.source : options.files[file]),
|
|
228
|
+
resolveModule: ({ importer, source }) => options.resolveSourceImport(importer, source),
|
|
229
|
+
});
|
|
230
|
+
const references = new Map<string, InferredServerActionExpressionReference>();
|
|
231
|
+
|
|
232
|
+
for (const action of graph.serverActions) {
|
|
233
|
+
const reference = {
|
|
234
|
+
end: action.end,
|
|
235
|
+
exportName: action.exportName,
|
|
236
|
+
expression: action.expression,
|
|
237
|
+
expressionEnd: action.expressionEnd,
|
|
238
|
+
expressionStart: action.expressionStart,
|
|
239
|
+
inferred: action.inferred,
|
|
240
|
+
moduleId: moduleIdForBuildFile(action.moduleFile, options.relativeRoutesDir),
|
|
241
|
+
sourceHash: options.sourceHash,
|
|
242
|
+
start: action.start,
|
|
243
|
+
};
|
|
244
|
+
references.set(formActionOccurrenceKey(reference), reference);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return references;
|
|
248
|
+
}
|
|
249
|
+
|
|
201
250
|
type RuntimeResolveResult =
|
|
202
251
|
| { kind: "dynamic" }
|
|
203
252
|
| { kind: "resolved"; reference: InferredServerActionReference }
|
package/src/vite.ts
CHANGED
|
@@ -15,16 +15,18 @@ import {
|
|
|
15
15
|
type ResolvedAppRouterProject,
|
|
16
16
|
} from "./config.js";
|
|
17
17
|
import type { AppRouterImportPolicy } from "./import-policy.js";
|
|
18
|
+
import {
|
|
19
|
+
collectClientRouteReferences,
|
|
20
|
+
detectNavigationRuntimeHint,
|
|
21
|
+
isClientRouteSource,
|
|
22
|
+
} from "./client-route-inference.js";
|
|
18
23
|
import {
|
|
19
24
|
buildNavigationRuntimeBundle,
|
|
20
25
|
buildClientRouteBundle,
|
|
21
26
|
buildClientRouteEntrySource,
|
|
22
27
|
clientScriptForPath,
|
|
23
|
-
collectClientRouteReferences,
|
|
24
|
-
detectNavigationRuntimeHint,
|
|
25
|
-
isClientRouteSource,
|
|
26
28
|
navigationRuntimeScriptForDev,
|
|
27
|
-
} from "./
|
|
29
|
+
} from "./navigation-runtime.js";
|
|
28
30
|
import { nodeRequestToWebRequest, sendResponse } from "./http.js";
|
|
29
31
|
import { renderAppRequest } from "./render.js";
|
|
30
32
|
import { stripRouteClientOnlyExports } from "./route-source.js";
|