@reckona/mreact-router 0.0.180 → 0.0.181
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/dist/adapters/cloudflare.d.ts.map +1 -1
- package/dist/adapters/cloudflare.js +53 -18
- package/dist/adapters/cloudflare.js.map +1 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +65 -12
- package/dist/build.js.map +1 -1
- package/package.json +11 -11
- package/src/adapters/cloudflare.ts +98 -41
- package/src/build.ts +93 -30
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reckona/mreact-router",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.181",
|
|
4
4
|
"description": "File-system app router, SSR, actions, and deployment adapters for mreact.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jsx",
|
|
@@ -105,20 +105,20 @@
|
|
|
105
105
|
},
|
|
106
106
|
"dependencies": {
|
|
107
107
|
"typescript": "^6.0.3",
|
|
108
|
-
"@reckona/mreact": "0.0.
|
|
109
|
-
"@reckona/mreact-compat": "0.0.
|
|
110
|
-
"@reckona/mreact-
|
|
111
|
-
"@reckona/mreact-
|
|
112
|
-
"@reckona/mreact-
|
|
113
|
-
"@reckona/mreact-reactive-core": "0.0.
|
|
114
|
-
"@reckona/mreact-reactive-dom": "0.0.
|
|
115
|
-
"@reckona/mreact-server": "0.0.
|
|
116
|
-
"@reckona/mreact-shared": "0.0.
|
|
108
|
+
"@reckona/mreact": "0.0.181",
|
|
109
|
+
"@reckona/mreact-compat": "0.0.181",
|
|
110
|
+
"@reckona/mreact-compiler": "0.0.181",
|
|
111
|
+
"@reckona/mreact-query": "0.0.181",
|
|
112
|
+
"@reckona/mreact-devtools": "0.0.181",
|
|
113
|
+
"@reckona/mreact-reactive-core": "0.0.181",
|
|
114
|
+
"@reckona/mreact-reactive-dom": "0.0.181",
|
|
115
|
+
"@reckona/mreact-server": "0.0.181",
|
|
116
|
+
"@reckona/mreact-shared": "0.0.181"
|
|
117
117
|
},
|
|
118
118
|
"peerDependencies": {
|
|
119
119
|
"vite": ">=8 <9"
|
|
120
120
|
},
|
|
121
121
|
"optionalDependencies": {
|
|
122
|
-
"@reckona/mreact-router-native": "0.0.
|
|
122
|
+
"@reckona/mreact-router-native": "0.0.181"
|
|
123
123
|
}
|
|
124
124
|
}
|
|
@@ -28,10 +28,11 @@ import {
|
|
|
28
28
|
requestLogFields,
|
|
29
29
|
type AppRouterLogger,
|
|
30
30
|
} from "../logger.js";
|
|
31
|
+
import { middlewareMatches, type MiddlewareModule } from "../middleware.js";
|
|
31
32
|
import { normalizeRoutePath } from "../route-path.js";
|
|
32
33
|
import type { AppRoute } from "../routes.js";
|
|
33
34
|
import { contentSecurityPolicy } from "../csp.js";
|
|
34
|
-
import { isNotFoundError } from "../navigation.js";
|
|
35
|
+
import { isNotFoundError, rewriteLocation } from "../navigation.js";
|
|
35
36
|
import { validateRouteMetadata } from "../metadata.js";
|
|
36
37
|
import { routeSecurityHeaders } from "../security-headers.js";
|
|
37
38
|
import type { AppRouterPrerenderStore } from "../serve.js";
|
|
@@ -202,7 +203,9 @@ export interface CloudflareMetadataRouteContext {
|
|
|
202
203
|
* Defines the default export accepted from a Cloudflare metadata route module.
|
|
203
204
|
*/
|
|
204
205
|
export interface CloudflareMetadataRouteModule {
|
|
205
|
-
default?:
|
|
206
|
+
default?:
|
|
207
|
+
| ((context: CloudflareMetadataRouteContext) => unknown | PromiseLike<unknown>)
|
|
208
|
+
| undefined;
|
|
206
209
|
}
|
|
207
210
|
|
|
208
211
|
/**
|
|
@@ -219,7 +222,9 @@ export type CloudflareRouteModuleRegistryEntry<Env = unknown> =
|
|
|
219
222
|
export type CloudflareRouteModuleRegistry<Env = unknown> = Record<
|
|
220
223
|
string,
|
|
221
224
|
| CloudflareRouteModuleRegistryEntry<Env>
|
|
222
|
-
| (() =>
|
|
225
|
+
| (() =>
|
|
226
|
+
| CloudflareRouteModuleRegistryEntry<Env>
|
|
227
|
+
| PromiseLike<CloudflareRouteModuleRegistryEntry<Env>>)
|
|
223
228
|
>;
|
|
224
229
|
|
|
225
230
|
/**
|
|
@@ -243,7 +248,9 @@ export interface CloudflareRouteModuleRendererOptions<Env = unknown> {
|
|
|
243
248
|
export type CloudflareRouteModuleGlob<Env = unknown> = Record<
|
|
244
249
|
string,
|
|
245
250
|
| CloudflareRouteModuleRegistryEntry<Env>
|
|
246
|
-
| (() =>
|
|
251
|
+
| (() =>
|
|
252
|
+
| CloudflareRouteModuleRegistryEntry<Env>
|
|
253
|
+
| PromiseLike<CloudflareRouteModuleRegistryEntry<Env>>)
|
|
247
254
|
>;
|
|
248
255
|
|
|
249
256
|
/**
|
|
@@ -317,6 +324,7 @@ export interface CloudflarePrerenderStoreOptions {
|
|
|
317
324
|
}
|
|
318
325
|
|
|
319
326
|
const clientPrefix = "/_mreact/client/";
|
|
327
|
+
const cloudflareMiddlewareRouteModuleKey = "__middleware__";
|
|
320
328
|
const defaultPrerenderCacheOrigin = "https://mreact.local";
|
|
321
329
|
const defaultPrerenderCachePrefix = "/_mreact/prerender";
|
|
322
330
|
|
|
@@ -375,10 +383,7 @@ export function createCloudflareBuiltRequestHandler<Env = unknown>(
|
|
|
375
383
|
return createCloudflareRequestHandler({
|
|
376
384
|
...options,
|
|
377
385
|
render(request, context) {
|
|
378
|
-
const matched = matchCloudflareRoute(
|
|
379
|
-
sortedRoutes,
|
|
380
|
-
new URL(request.url).pathname,
|
|
381
|
-
);
|
|
386
|
+
const matched = matchCloudflareRoute(sortedRoutes, new URL(request.url).pathname);
|
|
382
387
|
|
|
383
388
|
if (matched === undefined || options.renderRoute === undefined) {
|
|
384
389
|
return new Response("Not Found", { status: 404 });
|
|
@@ -402,6 +407,12 @@ export function createCloudflareRouteModuleRenderer<Env = unknown>(
|
|
|
402
407
|
options: CloudflareRouteModuleRendererOptions<Env>,
|
|
403
408
|
): NonNullable<CloudflareBuiltRequestHandlerOptions<Env>["renderRoute"]> {
|
|
404
409
|
return async (request, context) => {
|
|
410
|
+
const middlewareResult = await resolveCloudflareRouteModuleMiddleware(options.modules, request);
|
|
411
|
+
if (middlewareResult.type === "response") {
|
|
412
|
+
return middlewareResult.response;
|
|
413
|
+
}
|
|
414
|
+
request = middlewareResult.request;
|
|
415
|
+
|
|
405
416
|
if (context.route.kind !== "server" && isCloudflareNavigationRequest(request)) {
|
|
406
417
|
return cloudflareDocumentReloadNavigationResponse();
|
|
407
418
|
}
|
|
@@ -460,7 +471,9 @@ export function createCloudflareRouteModuleRenderer<Env = unknown>(
|
|
|
460
471
|
data =
|
|
461
472
|
pageModule.loader === undefined
|
|
462
473
|
? undefined
|
|
463
|
-
: await runWithCloudflareQueryClient(queryClient, () =>
|
|
474
|
+
: await runWithCloudflareQueryClient(queryClient, () =>
|
|
475
|
+
pageModule.loader!(loaderContext),
|
|
476
|
+
);
|
|
464
477
|
} catch (error) {
|
|
465
478
|
if (error instanceof Response) {
|
|
466
479
|
return error;
|
|
@@ -534,6 +547,39 @@ export function createCloudflareRouteModuleRenderer<Env = unknown>(
|
|
|
534
547
|
};
|
|
535
548
|
}
|
|
536
549
|
|
|
550
|
+
async function resolveCloudflareRouteModuleMiddleware<Env>(
|
|
551
|
+
modules: CloudflareRouteModuleRegistry<Env>,
|
|
552
|
+
request: Request,
|
|
553
|
+
): Promise<{ request: Request; type: "continue" } | { response: Response; type: "response" }> {
|
|
554
|
+
const module = (await loadCloudflareRouteModule(modules, cloudflareMiddlewareRouteModuleKey)) as
|
|
555
|
+
| MiddlewareModule
|
|
556
|
+
| undefined;
|
|
557
|
+
|
|
558
|
+
if (module === undefined || !middlewareMatches(module.config, new URL(request.url).pathname)) {
|
|
559
|
+
return { request, type: "continue" };
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
const middleware = module.middleware ?? module.default;
|
|
563
|
+
if (typeof middleware !== "function") {
|
|
564
|
+
return { request, type: "continue" };
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
const response = await middleware(request);
|
|
568
|
+
if (!(response instanceof Response)) {
|
|
569
|
+
return { request, type: "continue" };
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
const location = rewriteLocation(response);
|
|
573
|
+
if (location !== undefined) {
|
|
574
|
+
return {
|
|
575
|
+
request: new Request(new URL(location, request.url), request),
|
|
576
|
+
type: "continue",
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
return { response, type: "response" };
|
|
581
|
+
}
|
|
582
|
+
|
|
537
583
|
async function injectCloudflareQueryState<T extends Response | string>(
|
|
538
584
|
document: T,
|
|
539
585
|
state: DehydratedQueryClient,
|
|
@@ -605,7 +651,10 @@ async function runWithSerializedCloudflareQueryClient<T>(
|
|
|
605
651
|
const current = new Promise<void>((resolve) => {
|
|
606
652
|
releaseCurrent = resolve;
|
|
607
653
|
});
|
|
608
|
-
cloudflareQueryClientFallbackQueue = previous.then(
|
|
654
|
+
cloudflareQueryClientFallbackQueue = previous.then(
|
|
655
|
+
() => current,
|
|
656
|
+
() => current,
|
|
657
|
+
);
|
|
609
658
|
|
|
610
659
|
await previous;
|
|
611
660
|
|
|
@@ -669,7 +718,9 @@ async function dispatchCloudflareServerRoute<Env>(
|
|
|
669
718
|
context: CloudflareServerRouteContext<Env>,
|
|
670
719
|
): Promise<Response> {
|
|
671
720
|
const handler =
|
|
672
|
-
module[request.method as keyof CloudflareServerRouteModule<Env>] ??
|
|
721
|
+
module[request.method as keyof CloudflareServerRouteModule<Env>] ??
|
|
722
|
+
module.ALL ??
|
|
723
|
+
module.default;
|
|
673
724
|
|
|
674
725
|
if (typeof handler !== "function") {
|
|
675
726
|
return new Response("Method Not Allowed", { status: 405 });
|
|
@@ -728,17 +779,17 @@ function selectCloudflarePageComponent<Data, Env>(
|
|
|
728
779
|
return appExport as CloudflareRouteModuleComponent<Data, Env>;
|
|
729
780
|
}
|
|
730
781
|
|
|
731
|
-
const cloudflareRouteComponentExport = readCloudflareModuleExport(
|
|
782
|
+
const cloudflareRouteComponentExport = readCloudflareModuleExport(
|
|
783
|
+
module,
|
|
784
|
+
"CloudflareRouteComponent",
|
|
785
|
+
);
|
|
732
786
|
if (typeof cloudflareRouteComponentExport === "function") {
|
|
733
787
|
return cloudflareRouteComponentExport as CloudflareRouteModuleComponent<Data, Env>;
|
|
734
788
|
}
|
|
735
789
|
|
|
736
790
|
for (const name of Object.keys(module)) {
|
|
737
791
|
const value = readCloudflareModuleExport(module, name);
|
|
738
|
-
if (
|
|
739
|
-
!cloudflareReservedPageModuleExportNames.has(name) &&
|
|
740
|
-
typeof value === "function"
|
|
741
|
-
) {
|
|
792
|
+
if (!cloudflareReservedPageModuleExportNames.has(name) && typeof value === "function") {
|
|
742
793
|
return value as CloudflareRouteModuleComponent<Data, Env>;
|
|
743
794
|
}
|
|
744
795
|
}
|
|
@@ -759,7 +810,12 @@ function readCloudflareModuleExport(module: object, name: string): unknown {
|
|
|
759
810
|
return descriptor.get?.call(module);
|
|
760
811
|
}
|
|
761
812
|
|
|
762
|
-
const cloudflareDiagnosticPageModuleExportNames = [
|
|
813
|
+
const cloudflareDiagnosticPageModuleExportNames = [
|
|
814
|
+
"default",
|
|
815
|
+
"App",
|
|
816
|
+
"CloudflareRouteComponent",
|
|
817
|
+
"slots",
|
|
818
|
+
] as const;
|
|
763
819
|
|
|
764
820
|
// Fixed names + typeof only (never values) so the 500 response is useful without
|
|
765
821
|
// listing app-specific export names. Accessors are not invoked.
|
|
@@ -848,9 +904,10 @@ async function dispatchCloudflareMetadataRoute(
|
|
|
848
904
|
return new Response(body, {
|
|
849
905
|
headers: {
|
|
850
906
|
"cache-control": "public, max-age=3600",
|
|
851
|
-
"content-type":
|
|
852
|
-
|
|
853
|
-
|
|
907
|
+
"content-type":
|
|
908
|
+
typeof value === "string" && value.trimStart().startsWith("<svg")
|
|
909
|
+
? "image/svg+xml"
|
|
910
|
+
: "application/octet-stream",
|
|
854
911
|
},
|
|
855
912
|
});
|
|
856
913
|
}
|
|
@@ -1142,7 +1199,10 @@ async function handleCloudflareRequest<Env>(
|
|
|
1142
1199
|
return response;
|
|
1143
1200
|
}
|
|
1144
1201
|
|
|
1145
|
-
function isCloudflarePublicAssetPath(
|
|
1202
|
+
function isCloudflarePublicAssetPath(
|
|
1203
|
+
manifest: CloudflareClientManifest,
|
|
1204
|
+
pathname: string,
|
|
1205
|
+
): boolean {
|
|
1146
1206
|
return (manifest.publicAssets ?? []).includes(pathname);
|
|
1147
1207
|
}
|
|
1148
1208
|
|
|
@@ -1197,9 +1257,7 @@ function cacheControlHasDirective(cacheControl: string | null, directive: string
|
|
|
1197
1257
|
}
|
|
1198
1258
|
|
|
1199
1259
|
const normalizedDirective = directive.toLowerCase();
|
|
1200
|
-
return cacheControl
|
|
1201
|
-
.split(",")
|
|
1202
|
-
.some((part) => part.trim().toLowerCase() === normalizedDirective);
|
|
1260
|
+
return cacheControl.split(",").some((part) => part.trim().toLowerCase() === normalizedDirective);
|
|
1203
1261
|
}
|
|
1204
1262
|
|
|
1205
1263
|
function prerenderedResponse(
|
|
@@ -1228,10 +1286,7 @@ function prerenderedResponse(
|
|
|
1228
1286
|
});
|
|
1229
1287
|
}
|
|
1230
1288
|
|
|
1231
|
-
function cloudflareRouteRequiresModule(
|
|
1232
|
-
route: AppRoute,
|
|
1233
|
-
manifest: BuiltServerManifest,
|
|
1234
|
-
): boolean {
|
|
1289
|
+
function cloudflareRouteRequiresModule(route: AppRoute, manifest: BuiltServerManifest): boolean {
|
|
1235
1290
|
return (
|
|
1236
1291
|
route.kind === "metadata" ||
|
|
1237
1292
|
route.kind === "server" ||
|
|
@@ -1245,17 +1300,11 @@ function cloudflareRouteGlobKeyMatchesRoute(key: string, routeFile: string): boo
|
|
|
1245
1300
|
const normalizedKey = normalizeCloudflareRouteModulePath(key);
|
|
1246
1301
|
const normalizedRoute = normalizeCloudflareRouteModulePath(routeFile);
|
|
1247
1302
|
|
|
1248
|
-
return (
|
|
1249
|
-
normalizedKey === normalizedRoute ||
|
|
1250
|
-
normalizedKey.endsWith(`/${normalizedRoute}`)
|
|
1251
|
-
);
|
|
1303
|
+
return normalizedKey === normalizedRoute || normalizedKey.endsWith(`/${normalizedRoute}`);
|
|
1252
1304
|
}
|
|
1253
1305
|
|
|
1254
1306
|
function normalizeCloudflareRouteModulePath(path: string): string {
|
|
1255
|
-
const withoutPrefix = path
|
|
1256
|
-
.replace(/\\/g, "/")
|
|
1257
|
-
.replace(/^\.\//, "")
|
|
1258
|
-
.replace(/^\/+/, "");
|
|
1307
|
+
const withoutPrefix = path.replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/+/, "");
|
|
1259
1308
|
|
|
1260
1309
|
return withoutPrefix.replace(/\.(?:mjs|js|ts|tsx)$/, "");
|
|
1261
1310
|
}
|
|
@@ -1277,8 +1326,7 @@ function matchCloudflareRoute(
|
|
|
1277
1326
|
|
|
1278
1327
|
if (
|
|
1279
1328
|
catchAllIndex !== -1 &&
|
|
1280
|
-
pathSegments.length <
|
|
1281
|
-
catchAllIndex + 1 + route.segments.length - catchAllIndex - 1
|
|
1329
|
+
pathSegments.length < catchAllIndex + 1 + route.segments.length - catchAllIndex - 1
|
|
1282
1330
|
) {
|
|
1283
1331
|
continue;
|
|
1284
1332
|
}
|
|
@@ -1375,7 +1423,9 @@ function matchCloudflareRoute(
|
|
|
1375
1423
|
function compareCloudflareRoutes(a: AppRoute, b: AppRoute): number {
|
|
1376
1424
|
const scoreDelta = routeSpecificityScore(b) - routeSpecificityScore(a);
|
|
1377
1425
|
|
|
1378
|
-
return scoreDelta === 0
|
|
1426
|
+
return scoreDelta === 0
|
|
1427
|
+
? a.path.localeCompare(b.path) || a.kind.localeCompare(b.kind)
|
|
1428
|
+
: scoreDelta;
|
|
1379
1429
|
}
|
|
1380
1430
|
|
|
1381
1431
|
function routeSpecificityScore(route: AppRoute): number {
|
|
@@ -1537,7 +1587,9 @@ function isCloudflareRouteMetadata(value: RouteMetadata | undefined): value is R
|
|
|
1537
1587
|
return value !== undefined;
|
|
1538
1588
|
}
|
|
1539
1589
|
|
|
1540
|
-
function mergeCloudflareRouteMetadata(
|
|
1590
|
+
function mergeCloudflareRouteMetadata(
|
|
1591
|
+
metadata: readonly RouteMetadata[],
|
|
1592
|
+
): RouteMetadata | undefined {
|
|
1541
1593
|
if (metadata.length === 0) {
|
|
1542
1594
|
return undefined;
|
|
1543
1595
|
}
|
|
@@ -1562,7 +1614,12 @@ function mergeCloudflareRouteMetadata(metadata: readonly RouteMetadata[]): Route
|
|
|
1562
1614
|
...(icons === undefined ? {} : { icons }),
|
|
1563
1615
|
...(openGraph === undefined && openGraphImages === undefined
|
|
1564
1616
|
? {}
|
|
1565
|
-
: {
|
|
1617
|
+
: {
|
|
1618
|
+
openGraph: {
|
|
1619
|
+
...openGraph,
|
|
1620
|
+
...(openGraphImages === undefined ? {} : { images: openGraphImages }),
|
|
1621
|
+
},
|
|
1622
|
+
}),
|
|
1566
1623
|
};
|
|
1567
1624
|
|
|
1568
1625
|
return mergedMetadata;
|
package/src/build.ts
CHANGED
|
@@ -514,8 +514,8 @@ export async function buildApp(options: BuildAppOptions): Promise<BuildAppResult
|
|
|
514
514
|
}),
|
|
515
515
|
),
|
|
516
516
|
]);
|
|
517
|
-
const { artifacts: serverModules, sharedChunks: serverModuleSharedChunks } =
|
|
518
|
-
shouldTrackBuildPhases === false
|
|
517
|
+
const { artifacts: serverModules, sharedChunks: serverModuleSharedChunks } =
|
|
518
|
+
await (shouldTrackBuildPhases === false
|
|
519
519
|
? buildServerModuleArtifacts({
|
|
520
520
|
bundleRequestRuntimePackages: shouldBuildAwsLambda,
|
|
521
521
|
bundleCache: new Map(),
|
|
@@ -547,8 +547,7 @@ export async function buildApp(options: BuildAppOptions): Promise<BuildAppResult
|
|
|
547
547
|
serverTransformCache,
|
|
548
548
|
vitePlugins,
|
|
549
549
|
}),
|
|
550
|
-
)
|
|
551
|
-
);
|
|
550
|
+
));
|
|
552
551
|
const serverRoutes = routes.map((route) => ({
|
|
553
552
|
...route,
|
|
554
553
|
file: relative(project.projectRoot, route.file),
|
|
@@ -626,10 +625,7 @@ export async function buildApp(options: BuildAppOptions): Promise<BuildAppResult
|
|
|
626
625
|
...(navigationRuntimeScript === undefined ? [] : [navigationRuntimeScript]),
|
|
627
626
|
]),
|
|
628
627
|
).sort();
|
|
629
|
-
const serverModuleClosureFiles = buildServerModuleClosureManifest(
|
|
630
|
-
serverModules,
|
|
631
|
-
sourceAnalysis,
|
|
632
|
-
);
|
|
628
|
+
const serverModuleClosureFiles = buildServerModuleClosureManifest(serverModules, sourceAnalysis);
|
|
633
629
|
const prerenderedRoutes =
|
|
634
630
|
shouldTrackBuildPhases === false
|
|
635
631
|
? await prerenderStaticRoutes({
|
|
@@ -713,9 +709,7 @@ export async function buildApp(options: BuildAppOptions): Promise<BuildAppResult
|
|
|
713
709
|
...(serverActionManifest.allowedActions.length === 0
|
|
714
710
|
? {}
|
|
715
711
|
: { serverActionManifest: serverActionManifest.allowedActions }),
|
|
716
|
-
...(Object.keys(serverModuleClosureFiles).length === 0
|
|
717
|
-
? {}
|
|
718
|
-
: { serverModuleClosureFiles }),
|
|
712
|
+
...(Object.keys(serverModuleClosureFiles).length === 0 ? {} : { serverModuleClosureFiles }),
|
|
719
713
|
...(Object.keys(serverModuleArtifacts.files).length === 0
|
|
720
714
|
? {}
|
|
721
715
|
: { serverModuleFiles: serverModuleArtifacts.files }),
|
|
@@ -1051,13 +1045,7 @@ function collectManifestServerModuleClosureFiles(
|
|
|
1051
1045
|
for (const specifier of localManifestServerModuleSpecifiers(source)) {
|
|
1052
1046
|
const resolved = resolveManifestLocalServerSourceImport(file, specifier, sourceFiles);
|
|
1053
1047
|
if (resolved !== undefined) {
|
|
1054
|
-
collectManifestServerModuleClosureFiles(
|
|
1055
|
-
resolved,
|
|
1056
|
-
sourceAnalysis,
|
|
1057
|
-
sourceFiles,
|
|
1058
|
-
seen,
|
|
1059
|
-
closure,
|
|
1060
|
-
);
|
|
1048
|
+
collectManifestServerModuleClosureFiles(resolved, sourceAnalysis, sourceFiles, seen, closure);
|
|
1061
1049
|
}
|
|
1062
1050
|
}
|
|
1063
1051
|
}
|
|
@@ -2238,7 +2226,10 @@ async function buildServerModuleArtifacts(options: {
|
|
|
2238
2226
|
project: ResolvedAppRouterProject;
|
|
2239
2227
|
projectRoot: string;
|
|
2240
2228
|
routes: readonly AppRoute[];
|
|
2241
|
-
serverActionReferencesByFile: ReadonlyMap<
|
|
2229
|
+
serverActionReferencesByFile: ReadonlyMap<
|
|
2230
|
+
string,
|
|
2231
|
+
readonly BuiltServerActionExpressionReference[]
|
|
2232
|
+
>;
|
|
2242
2233
|
sourceAnalysis: BuildSourceAnalysisScope;
|
|
2243
2234
|
serverTransformCache: ServerTransformCache;
|
|
2244
2235
|
vitePlugins?: readonly PluginOption[] | undefined;
|
|
@@ -2323,11 +2314,7 @@ async function buildServerModuleArtifacts(options: {
|
|
|
2323
2314
|
continue;
|
|
2324
2315
|
}
|
|
2325
2316
|
|
|
2326
|
-
if (
|
|
2327
|
-
requestArtifactFiles.has(file) &&
|
|
2328
|
-
route?.kind !== "server" &&
|
|
2329
|
-
route?.kind !== "metadata"
|
|
2330
|
-
) {
|
|
2317
|
+
if (requestArtifactFiles.has(file) && route?.kind !== "server" && route?.kind !== "metadata") {
|
|
2331
2318
|
requestBatchEntries.push({
|
|
2332
2319
|
code: stripRouteRequestOnlyExports(source, absoluteFile),
|
|
2333
2320
|
filename: absoluteFile,
|
|
@@ -3138,6 +3125,8 @@ interface RouteRequestModuleBatchOutput {
|
|
|
3138
3125
|
sharedChunks: readonly SharedServerModuleChunk[];
|
|
3139
3126
|
}
|
|
3140
3127
|
|
|
3128
|
+
const cloudflareMiddlewareRouteModuleKey = "__middleware__";
|
|
3129
|
+
|
|
3141
3130
|
async function writeCloudflareRouteModules(options: {
|
|
3142
3131
|
cacheDir?: string | undefined;
|
|
3143
3132
|
cloudflareDir: string;
|
|
@@ -3195,6 +3184,26 @@ async function writeCloudflareRouteModules(options: {
|
|
|
3195
3184
|
root: options.projectRoot,
|
|
3196
3185
|
vitePlugins: options.vitePlugins,
|
|
3197
3186
|
});
|
|
3187
|
+
const cloudflareMiddlewareFile = findCloudflareMiddlewareFile({
|
|
3188
|
+
files: options.files,
|
|
3189
|
+
projectRoot: options.projectRoot,
|
|
3190
|
+
routesDir: options.routesDir,
|
|
3191
|
+
});
|
|
3192
|
+
const middlewareRouteModules = await buildCloudflareMiddlewareModuleBatch({
|
|
3193
|
+
cacheDir: options.cacheDir,
|
|
3194
|
+
define: options.define,
|
|
3195
|
+
root: options.projectRoot,
|
|
3196
|
+
routes:
|
|
3197
|
+
cloudflareMiddlewareFile === undefined
|
|
3198
|
+
? []
|
|
3199
|
+
: [
|
|
3200
|
+
{
|
|
3201
|
+
filename: cloudflareMiddlewareFile,
|
|
3202
|
+
routeId: cloudflareMiddlewareRouteModuleKey,
|
|
3203
|
+
},
|
|
3204
|
+
],
|
|
3205
|
+
vitePlugins: options.vitePlugins,
|
|
3206
|
+
});
|
|
3198
3207
|
const directComponentRoutes = await collectCloudflareDirectComponentRoutes({
|
|
3199
3208
|
requiredRoutes,
|
|
3200
3209
|
routesDir: options.routesDir,
|
|
@@ -3235,6 +3244,7 @@ async function writeCloudflareRouteModules(options: {
|
|
|
3235
3244
|
writeCloudflareBatchedRouteModuleChunks(options.cloudflareDir, loaderRouteModules),
|
|
3236
3245
|
writeCloudflareBatchedRouteModuleChunks(options.cloudflareDir, directComponentModules),
|
|
3237
3246
|
writeCloudflareBatchedRouteModuleChunks(options.cloudflareDir, stringShellComponentModules),
|
|
3247
|
+
writeCloudflareBatchedRouteModuleChunks(options.cloudflareDir, middlewareRouteModules),
|
|
3238
3248
|
]);
|
|
3239
3249
|
|
|
3240
3250
|
const registryEntries = await mapWithBuildConcurrency(
|
|
@@ -3354,6 +3364,7 @@ async function writeCloudflareRouteModules(options: {
|
|
|
3354
3364
|
|
|
3355
3365
|
const registrySource = [
|
|
3356
3366
|
`export const routeModules = {`,
|
|
3367
|
+
...cloudflareMiddlewareRegistryEntries(middlewareRouteModules),
|
|
3357
3368
|
...registryEntries.map((entry) => ` ${entry},`),
|
|
3358
3369
|
`};`,
|
|
3359
3370
|
`export default routeModules;`,
|
|
@@ -3365,6 +3376,31 @@ async function writeCloudflareRouteModules(options: {
|
|
|
3365
3376
|
return { registryFile: "route-modules.mjs" };
|
|
3366
3377
|
}
|
|
3367
3378
|
|
|
3379
|
+
function findCloudflareMiddlewareFile(options: {
|
|
3380
|
+
files: Record<string, string>;
|
|
3381
|
+
projectRoot: string;
|
|
3382
|
+
routesDir: string;
|
|
3383
|
+
}): string | undefined {
|
|
3384
|
+
const relativeRoutesDir = relative(options.projectRoot, options.routesDir).replaceAll(sep, "/");
|
|
3385
|
+
|
|
3386
|
+
const relativeFile = ["middleware.ts", "middleware.mreact.ts"]
|
|
3387
|
+
.map((file) => (relativeRoutesDir === "" ? file : `${relativeRoutesDir}/${file}`))
|
|
3388
|
+
.find((file) => options.files[file] !== undefined);
|
|
3389
|
+
|
|
3390
|
+
return relativeFile === undefined ? undefined : join(options.projectRoot, relativeFile);
|
|
3391
|
+
}
|
|
3392
|
+
|
|
3393
|
+
function cloudflareMiddlewareRegistryEntries(modules: CloudflareBatchedRouteModules): string[] {
|
|
3394
|
+
const middleware = modules.entries.get(cloudflareMiddlewareRouteModuleKey);
|
|
3395
|
+
if (middleware === undefined) {
|
|
3396
|
+
return [];
|
|
3397
|
+
}
|
|
3398
|
+
|
|
3399
|
+
return [
|
|
3400
|
+
` ${JSON.stringify(cloudflareMiddlewareRouteModuleKey)}: () => import(${JSON.stringify(`./${middleware.fileName}`)}),`,
|
|
3401
|
+
];
|
|
3402
|
+
}
|
|
3403
|
+
|
|
3368
3404
|
function cloudflarePageRouteFacadeModuleSource(componentImport: string): string {
|
|
3369
3405
|
return `import * as componentModule from ${JSON.stringify(componentImport)};
|
|
3370
3406
|
|
|
@@ -4904,6 +4940,27 @@ async function buildCloudflareRouteLoaderModuleBatch(options: {
|
|
|
4904
4940
|
});
|
|
4905
4941
|
}
|
|
4906
4942
|
|
|
4943
|
+
async function buildCloudflareMiddlewareModuleBatch(options: {
|
|
4944
|
+
cacheDir?: string | undefined;
|
|
4945
|
+
define?: UserConfig["define"] | undefined;
|
|
4946
|
+
routes: readonly { filename: string; routeId: string }[];
|
|
4947
|
+
root: string;
|
|
4948
|
+
vitePlugins?: readonly PluginOption[] | undefined;
|
|
4949
|
+
}): Promise<CloudflareBatchedRouteModules> {
|
|
4950
|
+
return await bundleCloudflareModuleBatch({
|
|
4951
|
+
cacheDir: options.cacheDir,
|
|
4952
|
+
define: options.define,
|
|
4953
|
+
entries: options.routes.map((route) => ({
|
|
4954
|
+
code: cloudflareMiddlewareModuleEntry(route.filename),
|
|
4955
|
+
filename: `${route.filename}.mreact-cloudflare-middleware.js`,
|
|
4956
|
+
name: `${route.routeId}.middleware`,
|
|
4957
|
+
routeId: route.routeId,
|
|
4958
|
+
})),
|
|
4959
|
+
root: options.root,
|
|
4960
|
+
vitePlugins: options.vitePlugins,
|
|
4961
|
+
});
|
|
4962
|
+
}
|
|
4963
|
+
|
|
4907
4964
|
export async function __buildCloudflareRouteLoaderModuleBatchForTests(options: {
|
|
4908
4965
|
cacheDir?: string | undefined;
|
|
4909
4966
|
define?: UserConfig["define"] | undefined;
|
|
@@ -5001,6 +5058,15 @@ function cloudflareRouteLoaderModuleEntry(filename: string): string {
|
|
|
5001
5058
|
return `export { loader } from ${JSON.stringify(filename)};`;
|
|
5002
5059
|
}
|
|
5003
5060
|
|
|
5061
|
+
function cloudflareMiddlewareModuleEntry(filename: string): string {
|
|
5062
|
+
return `import * as middlewareModule from ${JSON.stringify(filename)};
|
|
5063
|
+
|
|
5064
|
+
export const config = middlewareModule.config;
|
|
5065
|
+
export const middleware = middlewareModule.middleware;
|
|
5066
|
+
const defaultMiddleware = middlewareModule.default;
|
|
5067
|
+
export default defaultMiddleware;`;
|
|
5068
|
+
}
|
|
5069
|
+
|
|
5004
5070
|
async function buildCloudflareRouteMetadataExportModule(options: {
|
|
5005
5071
|
cacheDir?: string | undefined;
|
|
5006
5072
|
define?: UserConfig["define"] | undefined;
|
|
@@ -5678,10 +5744,7 @@ async function writeClientRouteBundles(options: {
|
|
|
5678
5744
|
await writeFile(join(options.clientDir, asset.fileName), source);
|
|
5679
5745
|
}
|
|
5680
5746
|
|
|
5681
|
-
const generatedAssets = new Set<string>([
|
|
5682
|
-
...routeCssAssets.assets,
|
|
5683
|
-
...specialCssAssets.assets,
|
|
5684
|
-
]);
|
|
5747
|
+
const generatedAssets = new Set<string>([...routeCssAssets.assets, ...specialCssAssets.assets]);
|
|
5685
5748
|
|
|
5686
5749
|
for (const chunk of output.chunks) {
|
|
5687
5750
|
generatedAssets.add(chunk.fileName);
|
|
@@ -5777,13 +5840,13 @@ async function writeSpecialRouteCssAssetBatches(options: {
|
|
|
5777
5840
|
|
|
5778
5841
|
return batch.css.length === 0
|
|
5779
5842
|
? undefined
|
|
5780
|
-
:
|
|
5843
|
+
: {
|
|
5781
5844
|
assets: batch.assets,
|
|
5782
5845
|
style: {
|
|
5783
5846
|
css: batch.css,
|
|
5784
5847
|
file: relative(options.appDir, file).split(sep).join("/"),
|
|
5785
5848
|
} satisfies ClientStyleManifestEntry,
|
|
5786
|
-
}
|
|
5849
|
+
};
|
|
5787
5850
|
});
|
|
5788
5851
|
|
|
5789
5852
|
return {
|