vinext 0.2.0 → 0.2.1
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/build/css-url-assets.d.ts +3 -1
- package/dist/build/css-url-assets.js +18 -1
- package/dist/build/inject-pregenerated-paths.d.ts +3 -0
- package/dist/build/inject-pregenerated-paths.js +4 -1
- package/dist/build/prerender-server-entry.d.ts +1 -0
- package/dist/build/prerender-server-entry.js +49 -0
- package/dist/build/prerender-server-pool.d.ts +44 -0
- package/dist/build/prerender-server-pool.js +194 -0
- package/dist/build/prerender.js +86 -22
- package/dist/build/run-prerender.js +2 -1
- package/dist/check.d.ts +4 -6
- package/dist/check.js +8 -9
- package/dist/cli.js +1 -1
- package/dist/client/vinext-next-data.d.ts +4 -1
- package/dist/config/config-matchers.js +33 -11
- package/dist/config/next-config.d.ts +36 -6
- package/dist/config/next-config.js +16 -2
- package/dist/entries/app-browser-entry.js +5 -1
- package/dist/entries/app-rsc-entry.d.ts +3 -2
- package/dist/entries/app-rsc-entry.js +4 -0
- package/dist/entries/pages-client-entry.js +14 -3
- package/dist/entries/pages-server-entry.js +18 -4
- package/dist/index.js +320 -25
- package/dist/packages/cloudflare/src/cache/kv-data-adapter.runtime.js +8 -1
- package/dist/packages/cloudflare/src/deploy.js +1 -5
- package/dist/packages/cloudflare/src/tpr.js +26 -5
- package/dist/plugins/fonts.js +1 -1
- package/dist/plugins/ignore-dynamic-requests.js +1 -1
- package/dist/plugins/og-assets.js +2 -1
- package/dist/plugins/optimize-imports.js +1 -1
- package/dist/plugins/rsc-reference-validation-normalizer.d.ts +12 -0
- package/dist/plugins/rsc-reference-validation-normalizer.js +48 -0
- package/dist/plugins/sass.d.ts +17 -1
- package/dist/plugins/sass.js +74 -1
- package/dist/plugins/styled-jsx.d.ts +16 -0
- package/dist/plugins/styled-jsx.js +149 -0
- package/dist/routing/app-route-graph.js +22 -16
- package/dist/routing/file-matcher.d.ts +8 -1
- package/dist/routing/file-matcher.js +15 -3
- package/dist/server/app-browser-entry.js +46 -14
- package/dist/server/app-browser-navigation-controller.js +1 -1
- package/dist/server/app-browser-server-action-client.js +5 -3
- package/dist/server/app-browser-state.d.ts +1 -0
- package/dist/server/app-browser-state.js +2 -2
- package/dist/server/app-browser-visible-commit.js +1 -1
- package/dist/server/app-page-boundary.js +2 -1
- package/dist/server/app-page-cache-finalizer.d.ts +1 -0
- package/dist/server/app-page-cache-finalizer.js +3 -3
- package/dist/server/app-page-cache.js +23 -6
- package/dist/server/app-page-dispatch.d.ts +1 -0
- package/dist/server/app-page-dispatch.js +25 -8
- package/dist/server/app-page-element-builder.js +1 -0
- package/dist/server/app-page-execution.js +2 -1
- package/dist/server/app-page-render-identity.d.ts +1 -0
- package/dist/server/app-page-render-identity.js +2 -1
- package/dist/server/app-page-render.d.ts +2 -0
- package/dist/server/app-page-render.js +67 -16
- package/dist/server/app-page-response.d.ts +7 -0
- package/dist/server/app-page-response.js +16 -4
- package/dist/server/app-page-stream.d.ts +2 -1
- package/dist/server/app-page-stream.js +1 -1
- package/dist/server/app-route-handler-execution.js +1 -1
- package/dist/server/app-route-tree-prefetch.d.ts +43 -0
- package/dist/server/app-route-tree-prefetch.js +187 -0
- package/dist/server/app-router-entry.js +1 -1
- package/dist/server/app-rsc-cache-busting.d.ts +2 -1
- package/dist/server/app-rsc-cache-busting.js +9 -4
- package/dist/server/app-rsc-handler.d.ts +6 -0
- package/dist/server/app-rsc-handler.js +89 -11
- package/dist/server/app-rsc-render-mode.d.ts +3 -2
- package/dist/server/app-rsc-render-mode.js +4 -1
- package/dist/server/app-rsc-request-normalization.d.ts +3 -4
- package/dist/server/app-rsc-request-normalization.js +4 -5
- package/dist/server/app-server-action-execution.js +4 -3
- package/dist/server/app-ssr-entry.js +3 -3
- package/dist/server/cache-control.d.ts +3 -1
- package/dist/server/cache-control.js +13 -1
- package/dist/server/dev-server.d.ts +11 -1
- package/dist/server/dev-server.js +78 -20
- package/dist/server/headers.d.ts +6 -2
- package/dist/server/headers.js +11 -5
- package/dist/server/isr-cache.d.ts +2 -1
- package/dist/server/isr-cache.js +7 -3
- package/dist/server/pages-data-route.d.ts +4 -2
- package/dist/server/pages-data-route.js +18 -4
- package/dist/server/pages-dev-module-url.d.ts +2 -1
- package/dist/server/pages-dev-module-url.js +6 -3
- package/dist/server/pages-node-compat.d.ts +12 -1
- package/dist/server/pages-node-compat.js +50 -1
- package/dist/server/pages-page-data.d.ts +9 -0
- package/dist/server/pages-page-data.js +17 -9
- package/dist/server/pages-page-handler.js +19 -7
- package/dist/server/pages-page-response.d.ts +1 -0
- package/dist/server/pages-page-response.js +3 -2
- package/dist/server/pages-request-pipeline.d.ts +8 -6
- package/dist/server/pages-request-pipeline.js +30 -6
- package/dist/server/pages-router-entry.js +1 -1
- package/dist/server/prod-server.d.ts +4 -2
- package/dist/server/prod-server.js +38 -22
- package/dist/server/request-pipeline.js +1 -1
- package/dist/shims/cache-handler.js +8 -1
- package/dist/shims/cache.js +3 -0
- package/dist/shims/fetch-cache.d.ts +3 -1
- package/dist/shims/fetch-cache.js +77 -52
- package/dist/shims/form.d.ts +1 -1
- package/dist/shims/internal/app-prefetch-fetch-queue.d.ts +10 -0
- package/dist/shims/internal/app-prefetch-fetch-queue.js +61 -0
- package/dist/shims/internal/hybrid-client-route-owner.d.ts +2 -1
- package/dist/shims/internal/hybrid-client-route-owner.js +34 -1
- package/dist/shims/internal/pages-data-fetch-dedup.d.ts +2 -1
- package/dist/shims/internal/pages-data-fetch-dedup.js +13 -2
- package/dist/shims/internal/pages-data-target.d.ts +8 -3
- package/dist/shims/internal/pages-data-target.js +9 -4
- package/dist/shims/link.d.ts +1 -1
- package/dist/shims/link.js +179 -42
- package/dist/shims/navigation.d.ts +15 -3
- package/dist/shims/navigation.js +202 -39
- package/dist/shims/navigation.react-server.js +1 -1
- package/dist/shims/request-context.js +18 -0
- package/dist/shims/router.js +31 -15
- package/dist/shims/unified-request-context.js +1 -0
- package/dist/typegen.js +1 -1
- package/dist/utils/middleware-request-headers.js +1 -1
- package/dist/utils/protocol-headers.d.ts +7 -1
- package/dist/utils/protocol-headers.js +7 -1
- package/dist/utils/vite-version.d.ts +2 -0
- package/dist/utils/vite-version.js +11 -1
- package/package.json +2 -2
|
@@ -27,8 +27,14 @@ function buildResponseTiming(options) {
|
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
29
|
function readRequestCacheLifeForPrerender(options) {
|
|
30
|
+
if (options.isEdgeRuntime && options.revalidateSeconds === null) return (options.peekRequestCacheLife?.() ?? options.getRequestCacheLife())?.revalidate !== void 0 ? { revalidate: 0 } : null;
|
|
30
31
|
return options.peekRequestCacheLife?.() ?? options.getRequestCacheLife();
|
|
31
32
|
}
|
|
33
|
+
function readRequestCacheLifeForCachePolicy(options) {
|
|
34
|
+
const requestCacheLife = options.getRequestCacheLife();
|
|
35
|
+
if (options.isEdgeRuntime && options.revalidateSeconds === null) return null;
|
|
36
|
+
return requestCacheLife;
|
|
37
|
+
}
|
|
32
38
|
function applyRequestCacheLife(options) {
|
|
33
39
|
let revalidateSeconds = options.revalidateSeconds;
|
|
34
40
|
let expireSeconds = options.expireSeconds;
|
|
@@ -40,6 +46,10 @@ function applyRequestCacheLife(options) {
|
|
|
40
46
|
revalidateSeconds
|
|
41
47
|
};
|
|
42
48
|
}
|
|
49
|
+
function resolveAppPageCacheWriteRevalidateSeconds(options) {
|
|
50
|
+
if (options.revalidateSeconds === null && (options.isForceStatic || options.isDynamicError)) return Infinity;
|
|
51
|
+
return options.revalidateSeconds;
|
|
52
|
+
}
|
|
43
53
|
function readRootBoundaryId(element) {
|
|
44
54
|
const rootLayoutTreePath = element[AppElementsWire.keys.rootLayout];
|
|
45
55
|
return typeof rootLayoutTreePath === "string" ? rootLayoutTreePath : null;
|
|
@@ -338,6 +348,8 @@ async function renderAppPageLifecycle(options) {
|
|
|
338
348
|
if (options.pprFallbackShellSignal) pprFallbackShellRsc = new Uint8Array(await readAppPageBinaryStream(rscStream));
|
|
339
349
|
let revalidateSeconds = options.revalidateSeconds;
|
|
340
350
|
let expireSeconds = options.expireSeconds;
|
|
351
|
+
const shouldWaitForAllReady = options.isPrerender === true && options.isSpeculativePrerender !== true;
|
|
352
|
+
const shouldReadRequestCacheLifeForPrerender = options.isPrerender === true;
|
|
341
353
|
const shouldCaptureRscForCacheMetadata = options.isProgressiveActionRender !== true && (options.isProduction || options.isPrerender === true) && (revalidateSeconds === null || revalidateSeconds > 0 && revalidateSeconds !== Infinity) && !options.isDraftMode && !options.isForceDynamic && !shouldBypassRscCacheForSkipTransport;
|
|
342
354
|
const createBufferedRscStream = (close) => new ReadableStream({ start(controller) {
|
|
343
355
|
if (pprFallbackShellRsc) controller.enqueue(pprFallbackShellRsc);
|
|
@@ -351,11 +363,13 @@ async function renderAppPageLifecycle(options) {
|
|
|
351
363
|
const capturedRscDataRef = { value: null };
|
|
352
364
|
if (rscCapture.sideStream && options.isRscRequest) capturedRscDataRef.value = readAppPageBinaryStream(rscCapture.sideStream);
|
|
353
365
|
if (options.isRscRequest) {
|
|
354
|
-
|
|
355
|
-
|
|
366
|
+
let requestCacheLifeForPrerender = null;
|
|
367
|
+
if (shouldWaitForAllReady) await settleCapturedRscRenderForCacheMetadata(capturedRscDataRef.value);
|
|
368
|
+
if (shouldReadRequestCacheLifeForPrerender) {
|
|
369
|
+
requestCacheLifeForPrerender = readRequestCacheLifeForPrerender(options);
|
|
356
370
|
({expireSeconds, revalidateSeconds} = applyRequestCacheLife({
|
|
357
371
|
expireSeconds,
|
|
358
|
-
requestCacheLife:
|
|
372
|
+
requestCacheLife: requestCacheLifeForPrerender,
|
|
359
373
|
revalidateSeconds
|
|
360
374
|
}));
|
|
361
375
|
}
|
|
@@ -378,6 +392,8 @@ async function renderAppPageLifecycle(options) {
|
|
|
378
392
|
mountedSlotsHeader: options.mountedSlotsHeader,
|
|
379
393
|
params: options.navigationParams,
|
|
380
394
|
policy: rscResponsePolicy,
|
|
395
|
+
renderedPathAndSearch: options.renderedPathAndSearch,
|
|
396
|
+
requestCacheLife: requestCacheLifeForPrerender,
|
|
381
397
|
timing: buildResponseTiming({
|
|
382
398
|
compileEnd,
|
|
383
399
|
handlerStart: options.handlerStart,
|
|
@@ -407,17 +423,22 @@ async function renderAppPageLifecycle(options) {
|
|
|
407
423
|
return options.getPageTags();
|
|
408
424
|
},
|
|
409
425
|
getRequestCacheLife() {
|
|
410
|
-
return options
|
|
426
|
+
return readRequestCacheLifeForCachePolicy(options);
|
|
411
427
|
},
|
|
412
428
|
isrDebug: options.isrDebug,
|
|
413
429
|
isrRscKey: options.isrRscKey,
|
|
414
430
|
isrSet: options.isrSet,
|
|
415
431
|
interceptionContext: options.interceptionContext,
|
|
416
432
|
mountedSlotsHeader: options.mountedSlotsHeader,
|
|
433
|
+
omitPendingDynamicCacheState: options.omitPendingDynamicCacheState,
|
|
417
434
|
renderMode: options.renderMode,
|
|
418
435
|
preserveClientResponseHeaders: rscResponsePolicy.cacheState !== "MISS",
|
|
419
436
|
expireSeconds,
|
|
420
|
-
revalidateSeconds
|
|
437
|
+
revalidateSeconds: resolveAppPageCacheWriteRevalidateSeconds({
|
|
438
|
+
isDynamicError: options.isDynamicError,
|
|
439
|
+
isForceStatic: options.isForceStatic,
|
|
440
|
+
revalidateSeconds
|
|
441
|
+
}),
|
|
421
442
|
waitUntil(promise) {
|
|
422
443
|
options.waitUntil?.(promise);
|
|
423
444
|
}
|
|
@@ -469,7 +490,8 @@ async function renderAppPageLifecycle(options) {
|
|
|
469
490
|
scriptNonce: options.scriptNonce,
|
|
470
491
|
sideStream: rscCapture.sideStream,
|
|
471
492
|
ssrHandler,
|
|
472
|
-
|
|
493
|
+
fallbackToErrorDocumentOnShellError: options.isPrerender === true && options.isSpeculativePrerender === true ? false : void 0,
|
|
494
|
+
waitForAllReady: shouldWaitForAllReady
|
|
473
495
|
});
|
|
474
496
|
},
|
|
475
497
|
renderSpecialErrorResponse(specialError) {
|
|
@@ -492,15 +514,27 @@ async function renderAppPageLifecycle(options) {
|
|
|
492
514
|
}
|
|
493
515
|
}
|
|
494
516
|
}
|
|
495
|
-
|
|
496
|
-
|
|
517
|
+
let requestCacheLifeForPrerender = null;
|
|
518
|
+
let dynamicUsedDuringRender = options.consumeDynamicUsage();
|
|
519
|
+
dynamicUsedDuringHtmlRender = dynamicUsedDuringRender;
|
|
520
|
+
const stopSpeculativeMetadataWaitOnDynamicUsage = options.isSpeculativePrerender === true && shouldReadRequestCacheLifeForPrerender ? () => {
|
|
521
|
+
if (dynamicUsedDuringRender || (options.peekDynamicUsage?.() ?? peekDynamicUsage())) {
|
|
522
|
+
dynamicUsedDuringRender = true;
|
|
523
|
+
dynamicUsedDuringHtmlRender = true;
|
|
524
|
+
return true;
|
|
525
|
+
}
|
|
526
|
+
return false;
|
|
527
|
+
} : void 0;
|
|
528
|
+
if (shouldWaitForAllReady || shouldReadRequestCacheLifeForPrerender) await settleCapturedRscRenderForCacheMetadata(htmlRender.capturedRscData, stopSpeculativeMetadataWaitOnDynamicUsage);
|
|
529
|
+
if (shouldReadRequestCacheLifeForPrerender) {
|
|
530
|
+
requestCacheLifeForPrerender = readRequestCacheLifeForPrerender(options);
|
|
497
531
|
({expireSeconds, revalidateSeconds} = applyRequestCacheLife({
|
|
498
532
|
expireSeconds,
|
|
499
|
-
requestCacheLife:
|
|
533
|
+
requestCacheLife: requestCacheLifeForPrerender,
|
|
500
534
|
revalidateSeconds
|
|
501
535
|
}));
|
|
502
536
|
}
|
|
503
|
-
|
|
537
|
+
dynamicUsedDuringRender = dynamicUsedDuringRender || options.consumeDynamicUsage();
|
|
504
538
|
dynamicUsedDuringHtmlRender = dynamicUsedDuringRender;
|
|
505
539
|
const draftCookie = options.getDraftModeCookieHeader();
|
|
506
540
|
let dynamicUsedBeforeContextCleanup = dynamicUsedDuringRender;
|
|
@@ -538,12 +572,13 @@ async function renderAppPageLifecycle(options) {
|
|
|
538
572
|
status: 500
|
|
539
573
|
},
|
|
540
574
|
policy: { cacheControl: NEVER_CACHE_CONTROL },
|
|
575
|
+
requestCacheLife: requestCacheLifeForPrerender,
|
|
541
576
|
timing: htmlResponseTiming
|
|
542
577
|
});
|
|
543
578
|
applyCdnResponseHeaders(response.headers, { cacheControl: NEVER_CACHE_CONTROL });
|
|
544
579
|
return response;
|
|
545
580
|
}
|
|
546
|
-
const shouldSpeculativelyWriteCache = options.isProduction && shouldCaptureRscForCacheMetadata && revalidateSeconds === null && !options.isDynamicError && !options.isForceStatic && !options.scriptNonce && options.isProgressiveActionRender !== true && !dynamicUsedDuringRender;
|
|
581
|
+
const shouldSpeculativelyWriteCache = options.isProduction && shouldCaptureRscForCacheMetadata && !options.isEdgeRuntime && revalidateSeconds === null && !options.isDynamicError && !options.isForceStatic && !options.scriptNonce && options.isProgressiveActionRender !== true && !dynamicUsedDuringRender;
|
|
547
582
|
if (htmlResponsePolicy.shouldWriteToCache || shouldSpeculativelyWriteCache) {
|
|
548
583
|
const isrResponse = buildAppPageHtmlResponse(safeHtmlStream, {
|
|
549
584
|
draftCookie,
|
|
@@ -551,6 +586,7 @@ async function renderAppPageLifecycle(options) {
|
|
|
551
586
|
isEdgeRuntime: options.isEdgeRuntime,
|
|
552
587
|
middlewareContext: options.middlewareContext,
|
|
553
588
|
policy: htmlResponsePolicy,
|
|
589
|
+
requestCacheLife: requestCacheLifeForPrerender,
|
|
554
590
|
timing: htmlResponseTiming
|
|
555
591
|
});
|
|
556
592
|
if (options.isPrerender === true) return isrResponse;
|
|
@@ -590,7 +626,7 @@ async function renderAppPageLifecycle(options) {
|
|
|
590
626
|
return options.getPageTags();
|
|
591
627
|
},
|
|
592
628
|
getRequestCacheLife() {
|
|
593
|
-
return options
|
|
629
|
+
return readRequestCacheLifeForCachePolicy(options);
|
|
594
630
|
},
|
|
595
631
|
isrDebug: options.isrDebug,
|
|
596
632
|
isrHtmlKey: options.isrHtmlKey,
|
|
@@ -600,7 +636,11 @@ async function renderAppPageLifecycle(options) {
|
|
|
600
636
|
omitPendingDynamicCacheState: options.omitPendingDynamicCacheState,
|
|
601
637
|
preserveClientResponseHeaders: !htmlResponsePolicy.shouldWriteToCache,
|
|
602
638
|
expireSeconds,
|
|
603
|
-
revalidateSeconds
|
|
639
|
+
revalidateSeconds: resolveAppPageCacheWriteRevalidateSeconds({
|
|
640
|
+
isDynamicError: options.isDynamicError,
|
|
641
|
+
isForceStatic: options.isForceStatic,
|
|
642
|
+
revalidateSeconds
|
|
643
|
+
}),
|
|
604
644
|
waitUntil(cachePromise) {
|
|
605
645
|
options.waitUntil?.(cachePromise);
|
|
606
646
|
}
|
|
@@ -612,14 +652,25 @@ async function renderAppPageLifecycle(options) {
|
|
|
612
652
|
isEdgeRuntime: options.isEdgeRuntime,
|
|
613
653
|
middlewareContext: options.middlewareContext,
|
|
614
654
|
policy: htmlResponsePolicy,
|
|
655
|
+
requestCacheLife: requestCacheLifeForPrerender,
|
|
615
656
|
timing: htmlResponseTiming
|
|
616
657
|
});
|
|
617
658
|
}
|
|
618
|
-
async function settleCapturedRscRenderForCacheMetadata(capturedRscDataPromise) {
|
|
659
|
+
async function settleCapturedRscRenderForCacheMetadata(capturedRscDataPromise, shouldStopWaiting) {
|
|
619
660
|
if (!capturedRscDataPromise) return;
|
|
661
|
+
if (!shouldStopWaiting) {
|
|
662
|
+
try {
|
|
663
|
+
await capturedRscDataPromise;
|
|
664
|
+
} catch {}
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
let settled = false;
|
|
668
|
+
const settledPromise = capturedRscDataPromise.catch(() => {}).then(() => {
|
|
669
|
+
settled = true;
|
|
670
|
+
});
|
|
620
671
|
try {
|
|
621
|
-
await
|
|
622
|
-
}
|
|
672
|
+
while (!settled && !shouldStopWaiting()) await Promise.race([settledPromise, new Promise((resolve) => setTimeout(resolve, 0))]);
|
|
673
|
+
} finally {}
|
|
623
674
|
}
|
|
624
675
|
//#endregion
|
|
625
676
|
export { renderAppPageLifecycle };
|
|
@@ -15,6 +15,10 @@ type AppPageResponsePolicy = {
|
|
|
15
15
|
cacheControl?: string;
|
|
16
16
|
cacheState?: "MISS" | "STATIC";
|
|
17
17
|
};
|
|
18
|
+
type AppPagePrerenderCacheLife = {
|
|
19
|
+
expire?: number;
|
|
20
|
+
revalidate?: number;
|
|
21
|
+
};
|
|
18
22
|
type ResolveAppPageResponsePolicyBaseOptions = {
|
|
19
23
|
isDraftMode: boolean;
|
|
20
24
|
isDynamicError: boolean;
|
|
@@ -42,6 +46,8 @@ type BuildAppPageRscResponseOptions = {
|
|
|
42
46
|
mountedSlotsHeader?: string | null;
|
|
43
47
|
params?: Record<string, unknown>;
|
|
44
48
|
policy: AppPageResponsePolicy;
|
|
49
|
+
renderedPathAndSearch?: string | null;
|
|
50
|
+
requestCacheLife?: AppPagePrerenderCacheLife | null;
|
|
45
51
|
timing?: AppPageResponseTiming;
|
|
46
52
|
};
|
|
47
53
|
type BuildAppPageHtmlResponseOptions = {
|
|
@@ -50,6 +56,7 @@ type BuildAppPageHtmlResponseOptions = {
|
|
|
50
56
|
isEdgeRuntime?: boolean;
|
|
51
57
|
middlewareContext: AppPageMiddlewareContext;
|
|
52
58
|
policy: AppPageResponsePolicy;
|
|
59
|
+
requestCacheLife?: AppPagePrerenderCacheLife | null;
|
|
53
60
|
timing?: AppPageResponseTiming;
|
|
54
61
|
};
|
|
55
62
|
declare function resolveAppPageRscResponsePolicy(options: ResolveAppPageRscResponsePolicyOptions): AppPageResponsePolicy;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { VINEXT_DYNAMIC_STALE_TIME_HEADER, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_PARAMS_HEADER, VINEXT_TIMING_HEADER } from "./headers.js";
|
|
1
|
+
import { VINEXT_DYNAMIC_STALE_TIME_HEADER, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_PARAMS_HEADER, VINEXT_PRERENDER_CACHE_LIFE_HEADER, VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, VINEXT_TIMING_HEADER } from "./headers.js";
|
|
2
2
|
import { setCacheStateHeaders } from "./cache-headers.js";
|
|
3
3
|
import { NO_STORE_CACHE_CONTROL, STATIC_CACHE_CONTROL, buildRevalidateCacheControl } from "./cache-control.js";
|
|
4
|
-
import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader } from "./app-rsc-cache-busting.js";
|
|
4
|
+
import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader } from "./app-rsc-cache-busting.js";
|
|
5
5
|
import { mergeMiddlewareResponseHeaders } from "./middleware-response-headers.js";
|
|
6
6
|
//#region src/server/app-page-response.ts
|
|
7
7
|
function applyTimingHeader(headers, timing) {
|
|
@@ -14,6 +14,14 @@ function applyTimingHeader(headers, timing) {
|
|
|
14
14
|
function applyDynamicStaleTimeHeader(headers, dynamicStaleTimeSeconds) {
|
|
15
15
|
if (dynamicStaleTimeSeconds !== void 0 && Number.isInteger(dynamicStaleTimeSeconds) && dynamicStaleTimeSeconds >= 0) headers.set(VINEXT_DYNAMIC_STALE_TIME_HEADER, String(dynamicStaleTimeSeconds));
|
|
16
16
|
}
|
|
17
|
+
function applyPrerenderCacheLifeHeader(headers, requestCacheLife) {
|
|
18
|
+
if (!requestCacheLife) return;
|
|
19
|
+
const payload = {};
|
|
20
|
+
if (typeof requestCacheLife.revalidate === "number" && Number.isFinite(requestCacheLife.revalidate)) payload.revalidate = requestCacheLife.revalidate;
|
|
21
|
+
if (typeof requestCacheLife.expire === "number" && Number.isFinite(requestCacheLife.expire)) payload.expire = requestCacheLife.expire;
|
|
22
|
+
if (payload.revalidate === void 0 && payload.expire === void 0) return;
|
|
23
|
+
headers.set(VINEXT_PRERENDER_CACHE_LIFE_HEADER, JSON.stringify(payload));
|
|
24
|
+
}
|
|
17
25
|
function resolveAppPageRscResponsePolicy(options) {
|
|
18
26
|
if (options.isDraftMode) return { cacheControl: NO_STORE_CACHE_CONTROL };
|
|
19
27
|
if (options.isForceDynamic || options.dynamicUsedDuringBuild) return { cacheControl: NO_STORE_CACHE_CONTROL };
|
|
@@ -51,8 +59,8 @@ function resolveAppPageHtmlResponsePolicy(options) {
|
|
|
51
59
|
};
|
|
52
60
|
if ((options.isForceStatic || options.isDynamicError) && options.revalidateSeconds === null) return {
|
|
53
61
|
cacheControl: STATIC_CACHE_CONTROL,
|
|
54
|
-
cacheState: "STATIC",
|
|
55
|
-
shouldWriteToCache:
|
|
62
|
+
cacheState: options.isProduction ? "MISS" : "STATIC",
|
|
63
|
+
shouldWriteToCache: options.isProduction
|
|
56
64
|
};
|
|
57
65
|
if (options.dynamicUsedDuringRender) return {
|
|
58
66
|
cacheControl: NO_STORE_CACHE_CONTROL,
|
|
@@ -92,7 +100,10 @@ function buildAppPageRscResponse(body, options) {
|
|
|
92
100
|
if (options.policy.cacheControl) headers.set("Cache-Control", options.policy.cacheControl);
|
|
93
101
|
if (options.policy.cacheState) setCacheStateHeaders(headers, options.policy.cacheState);
|
|
94
102
|
mergeMiddlewareResponseHeaders(headers, options.middlewareContext.headers);
|
|
103
|
+
if (options.renderedPathAndSearch) headers.set(VINEXT_RENDERED_PATH_AND_SEARCH_HEADER, encodeURIComponent(options.renderedPathAndSearch));
|
|
95
104
|
applyRscCompatibilityIdHeader(headers);
|
|
105
|
+
applyRscDeploymentIdHeader(headers);
|
|
106
|
+
applyPrerenderCacheLifeHeader(headers, options.requestCacheLife);
|
|
96
107
|
applyTimingHeader(headers, options.timing);
|
|
97
108
|
return new Response(body, {
|
|
98
109
|
status: options.middlewareContext.status ?? 200,
|
|
@@ -110,6 +121,7 @@ function buildAppPageHtmlResponse(body, options) {
|
|
|
110
121
|
if (options.draftCookie) headers.append("Set-Cookie", options.draftCookie);
|
|
111
122
|
if (options.linkHeader) headers.set("Link", options.linkHeader);
|
|
112
123
|
mergeMiddlewareResponseHeaders(headers, options.middlewareContext.headers);
|
|
124
|
+
applyPrerenderCacheLifeHeader(headers, options.requestCacheLife);
|
|
113
125
|
applyTimingHeader(headers, options.timing);
|
|
114
126
|
return new Response(body, {
|
|
115
127
|
status: options.middlewareContext.status ?? 200,
|
|
@@ -107,7 +107,8 @@ type RenderAppPageHtmlStreamOptions = {
|
|
|
107
107
|
value: Promise<ArrayBuffer> | null;
|
|
108
108
|
}; /** Abort signal for a build-time PPR fallback-shell static render. */
|
|
109
109
|
pprFallbackShellSignal?: AbortSignal; /** When true, wait for the full React tree before emitting bytes. */
|
|
110
|
-
waitForAllReady?: boolean; /**
|
|
110
|
+
waitForAllReady?: boolean; /** Override the default shell-error recovery decision passed to handleSsr. */
|
|
111
|
+
fallbackToErrorDocumentOnShellError?: boolean; /** Dev-only: original server error to surface in the browser overlay. */
|
|
111
112
|
initialDevServerError?: unknown;
|
|
112
113
|
/** True when the app supplies a custom global-error.tsx. Disables the
|
|
113
114
|
* default error-document shell fallback so SSR shell errors keep driving
|
|
@@ -68,7 +68,7 @@ async function renderAppPageHtmlStream(options) {
|
|
|
68
68
|
pprFallbackShellSignal: options.pprFallbackShellSignal,
|
|
69
69
|
waitForAllReady: options.waitForAllReady,
|
|
70
70
|
initialDevServerError: options.initialDevServerError,
|
|
71
|
-
fallbackToErrorDocumentOnShellError: options.waitForAllReady !== true && options.hasCustomGlobalError === false,
|
|
71
|
+
fallbackToErrorDocumentOnShellError: options.fallbackToErrorDocumentOnShellError ?? (options.waitForAllReady !== true && options.hasCustomGlobalError === false),
|
|
72
72
|
dynamicStaleTimeSeconds: options.dynamicStaleTimeSeconds,
|
|
73
73
|
getInitialNavigationCacheMetadata: options.getInitialNavigationCacheMetadata
|
|
74
74
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isDraftModeRequest, setHeadersContext } from "../shims/headers.js";
|
|
2
|
-
import { isPossibleAppRouteActionRequest } from "./app-action-request.js";
|
|
3
2
|
import { runWithRootParamsUsage } from "../shims/root-params.js";
|
|
3
|
+
import { isPossibleAppRouteActionRequest } from "./app-action-request.js";
|
|
4
4
|
import { applyRouteHandlerMiddlewareContext, applyRouteHandlerRevalidateHeader, assertSupportedAppRouteHandlerResponse, buildAppRouteCacheValue, finalizeRouteHandlerResponse, markRouteHandlerCacheMiss } from "./app-route-handler-response.js";
|
|
5
5
|
import { createTrackedAppRouteRequest, markKnownDynamicAppRoute } from "./app-route-handler-runtime.js";
|
|
6
6
|
import { createStaticGenerationHeadersContext, getAppRouteStaticGenerationErrorMessage } from "./app-static-generation.js";
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
//#region src/server/app-route-tree-prefetch.d.ts
|
|
2
|
+
type DynamicParamTypeShort = "d" | "c" | "oc";
|
|
3
|
+
type TreePrefetchParam = {
|
|
4
|
+
type: DynamicParamTypeShort;
|
|
5
|
+
key: null;
|
|
6
|
+
siblings: readonly string[] | null;
|
|
7
|
+
};
|
|
8
|
+
type AppRouteTreePrefetchSlot = {
|
|
9
|
+
configLayouts?: readonly unknown[] | null;
|
|
10
|
+
configLayoutTreePositions?: readonly number[] | null;
|
|
11
|
+
default?: unknown;
|
|
12
|
+
layout?: unknown;
|
|
13
|
+
layoutIndex?: number;
|
|
14
|
+
name: string;
|
|
15
|
+
page?: unknown;
|
|
16
|
+
routeSegments?: readonly string[] | null;
|
|
17
|
+
};
|
|
18
|
+
type AppRouteTreePrefetchRoute = {
|
|
19
|
+
layoutTreePositions?: readonly number[];
|
|
20
|
+
layouts?: readonly unknown[];
|
|
21
|
+
page?: unknown;
|
|
22
|
+
routeSegments: readonly string[];
|
|
23
|
+
slots?: Readonly<Record<string, AppRouteTreePrefetchSlot>> | null;
|
|
24
|
+
};
|
|
25
|
+
type TreePrefetch = {
|
|
26
|
+
name: string;
|
|
27
|
+
param: TreePrefetchParam | null;
|
|
28
|
+
prefetchHints: number;
|
|
29
|
+
slots: null | Record<string, TreePrefetch>;
|
|
30
|
+
};
|
|
31
|
+
type RouteTreePrefetchResponseOptions = {
|
|
32
|
+
buildId?: string | null;
|
|
33
|
+
deploymentId?: string;
|
|
34
|
+
prefetchInlining?: PrefetchInliningConfig;
|
|
35
|
+
};
|
|
36
|
+
type PrefetchInliningConfig = false | {
|
|
37
|
+
maxBundleSize: number;
|
|
38
|
+
maxSize: number;
|
|
39
|
+
};
|
|
40
|
+
declare function isRouteTreePrefetchRequest(request: Request): boolean;
|
|
41
|
+
declare function createRouteTreePrefetchResponse(route: AppRouteTreePrefetchRoute, options?: RouteTreePrefetchResponseOptions): Promise<Response>;
|
|
42
|
+
//#endregion
|
|
43
|
+
export { AppRouteTreePrefetchRoute, PrefetchInliningConfig, TreePrefetch, createRouteTreePrefetchResponse, isRouteTreePrefetchRequest };
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { NEXTJS_DEPLOYMENT_ID_HEADER } from "./headers.js";
|
|
2
|
+
import { getDeploymentId } from "../utils/deployment-id.js";
|
|
3
|
+
import { VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader } from "./app-rsc-cache-busting.js";
|
|
4
|
+
//#region src/server/app-route-tree-prefetch.ts
|
|
5
|
+
const PARENT_INLINED_INTO_SELF = 32;
|
|
6
|
+
const INLINED_INTO_CHILD = 64;
|
|
7
|
+
const HEAD_INLINED_INTO_SELF = 128;
|
|
8
|
+
const PAGE_SEGMENT = "__PAGE__";
|
|
9
|
+
const SLOT_SEGMENT = "(__SLOT__)";
|
|
10
|
+
const SEGMENT_INLINE_SIZE = 1;
|
|
11
|
+
const SEGMENT_OUTLINE_SIZE = 4096;
|
|
12
|
+
const DEFAULT_SEGMENT_INLINE_THRESHOLD = 2048;
|
|
13
|
+
const HEAD_INLINE_SIZE = 1;
|
|
14
|
+
const DEFAULT_MAX_INLINE_BUNDLE_SIZE = 10240;
|
|
15
|
+
const NEXT_DID_POSTPONE_HEADER = "x-nextjs-postponed";
|
|
16
|
+
function isRouteTreePrefetchRequest(request) {
|
|
17
|
+
return request.headers.get("RSC") === "1" && request.headers.get("Next-Router-Prefetch") === "1" && request.headers.get("Next-Router-Segment-Prefetch") === "/_tree";
|
|
18
|
+
}
|
|
19
|
+
function createNode(segment, module) {
|
|
20
|
+
const { name, param } = routeTreeSegment(segment);
|
|
21
|
+
return {
|
|
22
|
+
name,
|
|
23
|
+
param,
|
|
24
|
+
prefetchSize: estimatePrefetchSize(module) ?? ((module === null || module === void 0) && segment !== PAGE_SEGMENT ? SEGMENT_INLINE_SIZE : null),
|
|
25
|
+
prefetchHints: 0,
|
|
26
|
+
slots: null
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function ensureSlots(node) {
|
|
30
|
+
if (node.slots === null) node.slots = {};
|
|
31
|
+
return node.slots;
|
|
32
|
+
}
|
|
33
|
+
function addChild(node, key, child) {
|
|
34
|
+
ensureSlots(node)[key] = child;
|
|
35
|
+
}
|
|
36
|
+
function routeTreeSegment(segment) {
|
|
37
|
+
if (segment.startsWith(":")) {
|
|
38
|
+
const rest = segment.slice(1);
|
|
39
|
+
if (rest.endsWith("+")) return dynamicRouteTreeSegment(rest.slice(0, -1), "c");
|
|
40
|
+
if (rest.endsWith("*")) return dynamicRouteTreeSegment(rest.slice(0, -1), "oc");
|
|
41
|
+
return dynamicRouteTreeSegment(rest, "d");
|
|
42
|
+
}
|
|
43
|
+
if (segment.startsWith("[[...") && segment.endsWith("]]")) return dynamicRouteTreeSegment(segment.slice(5, -2), "oc");
|
|
44
|
+
if (segment.startsWith("[...") && segment.endsWith("]")) return dynamicRouteTreeSegment(segment.slice(4, -1), "c");
|
|
45
|
+
if (segment.startsWith("[") && segment.endsWith("]")) return dynamicRouteTreeSegment(segment.slice(1, -1), "d");
|
|
46
|
+
return {
|
|
47
|
+
name: segment,
|
|
48
|
+
param: null
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function dynamicRouteTreeSegment(name, type) {
|
|
52
|
+
return {
|
|
53
|
+
name,
|
|
54
|
+
param: {
|
|
55
|
+
key: null,
|
|
56
|
+
siblings: null,
|
|
57
|
+
type
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function explicitPrefetchSize(module) {
|
|
62
|
+
if (typeof module !== "object" || module === null) return null;
|
|
63
|
+
const value = module.prefetchSize;
|
|
64
|
+
if (value === "large") return SEGMENT_OUTLINE_SIZE;
|
|
65
|
+
if (value === "small") return SEGMENT_INLINE_SIZE;
|
|
66
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
|
|
67
|
+
}
|
|
68
|
+
function estimatePrefetchSize(module) {
|
|
69
|
+
const explicitSize = explicitPrefetchSize(module);
|
|
70
|
+
if (explicitSize !== null) return explicitSize;
|
|
71
|
+
if (typeof module !== "object" || module === null) return null;
|
|
72
|
+
return typeof module.default === "function" ? SEGMENT_INLINE_SIZE : null;
|
|
73
|
+
}
|
|
74
|
+
function layoutModuleByTreePosition(route) {
|
|
75
|
+
const layouts = route.layouts ?? [];
|
|
76
|
+
const positions = route.layoutTreePositions ?? [];
|
|
77
|
+
const byPosition = /* @__PURE__ */ new Map();
|
|
78
|
+
for (const [index, position] of positions.entries()) byPosition.set(position, layouts[index]);
|
|
79
|
+
return byPosition;
|
|
80
|
+
}
|
|
81
|
+
function modulesByTreePosition(modules, positions) {
|
|
82
|
+
const byPosition = /* @__PURE__ */ new Map();
|
|
83
|
+
for (const [index, position] of (positions ?? []).entries()) byPosition.set(position, modules?.[index]);
|
|
84
|
+
return byPosition;
|
|
85
|
+
}
|
|
86
|
+
async function buildTree(route) {
|
|
87
|
+
const layoutsByPosition = layoutModuleByTreePosition(route);
|
|
88
|
+
const root = createNode("", layoutsByPosition.get(0));
|
|
89
|
+
const nodesByPosition = new Map([[0, root]]);
|
|
90
|
+
let current = root;
|
|
91
|
+
for (const [index, segment] of route.routeSegments.entries()) {
|
|
92
|
+
const position = index + 1;
|
|
93
|
+
const child = createNode(segment, layoutsByPosition.get(position));
|
|
94
|
+
addChild(current, "children", child);
|
|
95
|
+
nodesByPosition.set(position, child);
|
|
96
|
+
current = child;
|
|
97
|
+
}
|
|
98
|
+
addChild(current, "children", createNode(PAGE_SEGMENT, route.page));
|
|
99
|
+
for (const slot of Object.values(route.slots ?? {})) {
|
|
100
|
+
const ownerPosition = slot.layoutIndex === void 0 || slot.layoutIndex < 0 ? route.routeSegments.length : route.layoutTreePositions?.[slot.layoutIndex] ?? route.routeSegments.length;
|
|
101
|
+
const owner = nodesByPosition.get(ownerPosition) ?? current;
|
|
102
|
+
const slotRoot = createNode(SLOT_SEGMENT, slot.layout);
|
|
103
|
+
let slotCurrent = slotRoot;
|
|
104
|
+
const slotConfigLayoutsByPosition = modulesByTreePosition(slot.configLayouts, slot.configLayoutTreePositions);
|
|
105
|
+
const slotRouteSegments = slot.routeSegments ?? [];
|
|
106
|
+
for (const [index, segment] of slotRouteSegments.entries()) {
|
|
107
|
+
const position = index + 1;
|
|
108
|
+
const child = createNode(segment, slotConfigLayoutsByPosition.get(position));
|
|
109
|
+
addChild(slotCurrent, "children", child);
|
|
110
|
+
slotCurrent = child;
|
|
111
|
+
}
|
|
112
|
+
addChild(slotCurrent, "children", createNode(PAGE_SEGMENT, slot.page ?? slot.default));
|
|
113
|
+
addChild(owner, slot.name, slotRoot);
|
|
114
|
+
}
|
|
115
|
+
return root;
|
|
116
|
+
}
|
|
117
|
+
function computePrefetchHints(node, parentGzipSize, headInlineState, config) {
|
|
118
|
+
const currentGzipSize = node.prefetchSize;
|
|
119
|
+
const sizeToInline = currentGzipSize !== null && currentGzipSize < config.maxSize ? currentGzipSize : null;
|
|
120
|
+
let didInlineIntoChild = false;
|
|
121
|
+
let acceptingChildInlinedBytes = 0;
|
|
122
|
+
let smallestChildInlinedBytes = Number.POSITIVE_INFINITY;
|
|
123
|
+
let hasChildren = false;
|
|
124
|
+
for (const child of Object.values(node.slots ?? {})) {
|
|
125
|
+
hasChildren = true;
|
|
126
|
+
const childInlinedBytes = computePrefetchHints(child, didInlineIntoChild ? null : sizeToInline, headInlineState, config);
|
|
127
|
+
if ((child.prefetchHints & PARENT_INLINED_INTO_SELF) !== 0) {
|
|
128
|
+
didInlineIntoChild = true;
|
|
129
|
+
acceptingChildInlinedBytes = childInlinedBytes;
|
|
130
|
+
} else if (!didInlineIntoChild && childInlinedBytes < smallestChildInlinedBytes) smallestChildInlinedBytes = childInlinedBytes;
|
|
131
|
+
}
|
|
132
|
+
if (!hasChildren) smallestChildInlinedBytes = 0;
|
|
133
|
+
let hints = node.prefetchHints;
|
|
134
|
+
if (didInlineIntoChild) hints |= INLINED_INTO_CHILD;
|
|
135
|
+
let inlinedBytes = didInlineIntoChild ? acceptingChildInlinedBytes : smallestChildInlinedBytes;
|
|
136
|
+
const isBundleTerminal = !didInlineIntoChild;
|
|
137
|
+
if (!headInlineState.inlined && isBundleTerminal && node.name === PAGE_SEGMENT && inlinedBytes + HEAD_INLINE_SIZE < config.maxBundleSize) {
|
|
138
|
+
hints |= HEAD_INLINED_INTO_SELF;
|
|
139
|
+
inlinedBytes += HEAD_INLINE_SIZE;
|
|
140
|
+
headInlineState.inlined = true;
|
|
141
|
+
}
|
|
142
|
+
if (parentGzipSize !== null) {
|
|
143
|
+
if (inlinedBytes + parentGzipSize < config.maxBundleSize) {
|
|
144
|
+
hints |= PARENT_INLINED_INTO_SELF;
|
|
145
|
+
inlinedBytes += parentGzipSize;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
node.prefetchHints = hints;
|
|
149
|
+
return inlinedBytes;
|
|
150
|
+
}
|
|
151
|
+
function stripMutableFields(node) {
|
|
152
|
+
const slots = node.slots === null ? null : Object.fromEntries(Object.entries(node.slots).map(([key, child]) => [key, stripMutableFields(child)]));
|
|
153
|
+
return {
|
|
154
|
+
name: node.name,
|
|
155
|
+
param: node.param,
|
|
156
|
+
prefetchHints: node.prefetchHints,
|
|
157
|
+
slots
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function resolvePrefetchInliningConfig(config) {
|
|
161
|
+
if (config) return config;
|
|
162
|
+
return {
|
|
163
|
+
maxBundleSize: DEFAULT_MAX_INLINE_BUNDLE_SIZE,
|
|
164
|
+
maxSize: DEFAULT_SEGMENT_INLINE_THRESHOLD
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
async function createRouteTreePrefetchResponse(route, options = {}) {
|
|
168
|
+
const tree = await buildTree(route);
|
|
169
|
+
computePrefetchHints(tree, null, { inlined: false }, resolvePrefetchInliningConfig(options.prefetchInlining));
|
|
170
|
+
const headers = new Headers({
|
|
171
|
+
"Cache-Control": "no-store",
|
|
172
|
+
"Content-Type": VINEXT_RSC_CONTENT_TYPE,
|
|
173
|
+
[NEXT_DID_POSTPONE_HEADER]: "2",
|
|
174
|
+
Vary: VINEXT_RSC_VARY_HEADER
|
|
175
|
+
});
|
|
176
|
+
applyRscCompatibilityIdHeader(headers);
|
|
177
|
+
const deploymentId = options.deploymentId ?? getDeploymentId();
|
|
178
|
+
if (deploymentId) headers.set(NEXTJS_DEPLOYMENT_ID_HEADER, deploymentId);
|
|
179
|
+
const payload = {
|
|
180
|
+
tree: stripMutableFields(tree),
|
|
181
|
+
staleTime: -1
|
|
182
|
+
};
|
|
183
|
+
if (options.buildId) payload.buildId = options.buildId;
|
|
184
|
+
return new Response(`0:${JSON.stringify(payload)}\n`, { headers });
|
|
185
|
+
}
|
|
186
|
+
//#endregion
|
|
187
|
+
export { createRouteTreePrefetchResponse, isRouteTreePrefetchRequest };
|
|
@@ -4,8 +4,8 @@ import { VINEXT_PRERENDER_ROUTE_PARAMS_HEADER } from "../utils/protocol-headers.
|
|
|
4
4
|
import { badRequestResponse, notFoundResponse, notFoundStaticAssetResponse } from "./http-error-responses.js";
|
|
5
5
|
import { isOpenRedirectShaped } from "./open-redirect.js";
|
|
6
6
|
import { cloneRequestWithHeaders, filterInternalHeaders } from "./request-pipeline.js";
|
|
7
|
-
import { getImageOptimizer, handleConfiguredImageOptimization, isImageOptimizationPath } from "./image-optimization.js";
|
|
8
7
|
import { assetPrefixPathname, isNextStaticPath } from "../utils/asset-prefix.js";
|
|
8
|
+
import { getImageOptimizer, handleConfiguredImageOptimization, isImageOptimizationPath } from "./image-optimization.js";
|
|
9
9
|
import { finalizeMissingStaticAssetResponse, resolveStaticAssetSignal } from "./worker-utils.js";
|
|
10
10
|
import { readTrustedPrerenderRouteParams, serializePrerenderRouteParamsHeader } from "./prerender-route-params.js";
|
|
11
11
|
import rscHandler, { __assetPrefix, __basePath, __imageAllowedWidths, __imageConfig } from "virtual:vinext-rsc-entry";
|
|
@@ -24,6 +24,7 @@ type ResolveInvalidRscCacheBustingRequestOptions = {
|
|
|
24
24
|
};
|
|
25
25
|
declare function getVinextRscCompatibilityId(): string | null;
|
|
26
26
|
declare function applyRscCompatibilityIdHeader(headers: Headers, compatibilityId?: string | null | undefined): void;
|
|
27
|
+
declare function applyRscDeploymentIdHeader(headers: Headers): void;
|
|
27
28
|
declare function isRscCompatibilityIdCompatible(responseCompatibilityId: string | null | undefined, clientCompatibilityId?: string | null | undefined): boolean;
|
|
28
29
|
type RscCompatibilityNavigationDecision = {
|
|
29
30
|
kind: "compatible";
|
|
@@ -61,4 +62,4 @@ declare function createServerActionRequestUrl(href: string): string;
|
|
|
61
62
|
declare function createRscRedirectLocation(location: string, request: Request): Promise<string>;
|
|
62
63
|
declare function resolveInvalidRscCacheBustingRequest(options: ResolveInvalidRscCacheBustingRequestOptions): Promise<Response | null>;
|
|
63
64
|
//#endregion
|
|
64
|
-
export { VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, computeRscCacheBustingSearchParam, createRscRedirectLocation, createRscRequestHeaders, createRscRequestUrl, createServerActionRequestUrl, getVinextRscCompatibilityId, hasRscCacheBustingSearchParam, isRscCompatibilityIdCompatible, resolveHardNavigationTargetFromRscResponse, resolveInvalidRscCacheBustingRequest, resolveRscCompatibilityNavigationDecision, setRscCacheBustingSearchParam, stripRscCacheBustingSearchParam, stripRscSuffix };
|
|
65
|
+
export { VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader, computeRscCacheBustingSearchParam, createRscRedirectLocation, createRscRequestHeaders, createRscRequestUrl, createServerActionRequestUrl, getVinextRscCompatibilityId, hasRscCacheBustingSearchParam, isRscCompatibilityIdCompatible, resolveHardNavigationTargetFromRscResponse, resolveInvalidRscCacheBustingRequest, resolveRscCompatibilityNavigationDecision, setRscCacheBustingSearchParam, stripRscCacheBustingSearchParam, stripRscSuffix };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { NEXT_ROUTER_PREFETCH_HEADER, NEXT_ROUTER_SEGMENT_PREFETCH_HEADER, NEXT_ROUTER_STATE_TREE_HEADER, NEXT_URL_HEADER, VINEXT_CLIENT_REUSE_MANIFEST_HEADER, VINEXT_INTERCEPTION_CONTEXT_HEADER, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_RSC_RENDER_MODE_HEADER } from "./headers.js";
|
|
1
|
+
import { NEXTJS_DEPLOYMENT_ID_HEADER, NEXT_ROUTER_PREFETCH_HEADER, NEXT_ROUTER_SEGMENT_PREFETCH_HEADER, NEXT_ROUTER_STATE_TREE_HEADER, NEXT_URL_HEADER, VINEXT_CLIENT_REUSE_MANIFEST_HEADER, VINEXT_INTERCEPTION_CONTEXT_HEADER, VINEXT_MOUNTED_SLOTS_HEADER, VINEXT_RSC_RENDER_MODE_HEADER } from "./headers.js";
|
|
2
2
|
import { fnv1a64 } from "../utils/hash.js";
|
|
3
3
|
import { parseAppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
4
|
-
import { applyDeploymentIdHeader } from "../utils/deployment-id.js";
|
|
4
|
+
import { applyDeploymentIdHeader, getDeploymentId } from "../utils/deployment-id.js";
|
|
5
5
|
//#region src/server/app-rsc-cache-busting.ts
|
|
6
6
|
/**
|
|
7
7
|
* RSC cache-busting hashes cover the headers that make an RSC payload vary.
|
|
@@ -44,6 +44,11 @@ function applyRscCompatibilityIdHeader(headers, compatibilityId = getVinextRscCo
|
|
|
44
44
|
if (normalized) headers.set(VINEXT_RSC_COMPATIBILITY_ID_HEADER, normalized);
|
|
45
45
|
else headers.delete(VINEXT_RSC_COMPATIBILITY_ID_HEADER);
|
|
46
46
|
}
|
|
47
|
+
function applyRscDeploymentIdHeader(headers) {
|
|
48
|
+
const deploymentId = getDeploymentId();
|
|
49
|
+
if (deploymentId) headers.set(NEXTJS_DEPLOYMENT_ID_HEADER, deploymentId);
|
|
50
|
+
else headers.delete(NEXTJS_DEPLOYMENT_ID_HEADER);
|
|
51
|
+
}
|
|
47
52
|
function isRscCompatibilityIdCompatible(responseCompatibilityId, clientCompatibilityId = getVinextRscCompatibilityId()) {
|
|
48
53
|
const normalizedResponseCompatibilityId = normalizeCompatibilityId(responseCompatibilityId);
|
|
49
54
|
const normalizedClientCompatibilityId = normalizeCompatibilityId(clientCompatibilityId);
|
|
@@ -184,7 +189,7 @@ async function resolveInvalidRscCacheBustingRequest(options) {
|
|
|
184
189
|
const url = new URL(options.request.url);
|
|
185
190
|
const actualHash = url.searchParams.get(VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM);
|
|
186
191
|
const expectedHash = await computeRscCacheBustingSearchParam(options.request.headers);
|
|
187
|
-
if (actualHash === null && expectedHash === "") return null;
|
|
192
|
+
if (actualHash === null && expectedHash === "" && url.pathname.endsWith(".rsc")) return null;
|
|
188
193
|
const acceptedHashes = new Set([expectedHash]);
|
|
189
194
|
if (actualHash !== null && actualHash !== expectedHash) {
|
|
190
195
|
acceptedHashes.add(computeLegacyRscCacheBustingSearchParam(options.request.headers));
|
|
@@ -203,4 +208,4 @@ async function resolveInvalidRscCacheBustingRequest(options) {
|
|
|
203
208
|
});
|
|
204
209
|
}
|
|
205
210
|
//#endregion
|
|
206
|
-
export { VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, computeRscCacheBustingSearchParam, createRscRedirectLocation, createRscRequestHeaders, createRscRequestUrl, createServerActionRequestUrl, getVinextRscCompatibilityId, hasRscCacheBustingSearchParam, isRscCompatibilityIdCompatible, resolveHardNavigationTargetFromRscResponse, resolveInvalidRscCacheBustingRequest, resolveRscCompatibilityNavigationDecision, setRscCacheBustingSearchParam, stripRscCacheBustingSearchParam, stripRscSuffix };
|
|
211
|
+
export { VINEXT_RSC_CACHE_BUSTING_SEARCH_PARAM, VINEXT_RSC_COMPATIBILITY_ID_HEADER, VINEXT_RSC_CONTENT_TYPE, VINEXT_RSC_RENDER_MODE_HEADER, VINEXT_RSC_VARY_HEADER, applyRscCompatibilityIdHeader, applyRscDeploymentIdHeader, computeRscCacheBustingSearchParam, createRscRedirectLocation, createRscRequestHeaders, createRscRequestUrl, createServerActionRequestUrl, getVinextRscCompatibilityId, hasRscCacheBustingSearchParam, isRscCompatibilityIdCompatible, resolveHardNavigationTargetFromRscResponse, resolveInvalidRscCacheBustingRequest, resolveRscCompatibilityNavigationDecision, setRscCacheBustingSearchParam, stripRscCacheBustingSearchParam, stripRscSuffix };
|
|
@@ -6,6 +6,7 @@ import { AppMiddlewareContext, ApplyAppMiddlewareResult } from "./app-middleware
|
|
|
6
6
|
import { AppRscRenderMode } from "./app-rsc-render-mode.js";
|
|
7
7
|
import { AppPagePprFallbackCacheShell } from "./app-ppr-fallback-shell.js";
|
|
8
8
|
import { AppPrerenderRootParamNamesMap, AppPrerenderStaticParamsMap } from "./app-prerender-endpoints.js";
|
|
9
|
+
import { AppRouteTreePrefetchRoute, PrefetchInliningConfig } from "./app-route-tree-prefetch.js";
|
|
9
10
|
import { ReactFormState } from "react-dom/client";
|
|
10
11
|
|
|
11
12
|
//#region src/server/app-rsc-handler.d.ts
|
|
@@ -24,12 +25,15 @@ type AppRscHandlerRoute = {
|
|
|
24
25
|
__loadPage?: unknown;
|
|
25
26
|
__loadRouteHandler?: unknown;
|
|
26
27
|
isDynamic: boolean;
|
|
28
|
+
layouts?: readonly unknown[];
|
|
29
|
+
layoutTreePositions?: readonly number[];
|
|
27
30
|
params?: readonly string[];
|
|
28
31
|
page?: unknown;
|
|
29
32
|
pattern: string;
|
|
30
33
|
rootParamNames?: readonly string[];
|
|
31
34
|
routeHandler?: unknown;
|
|
32
35
|
routeSegments: readonly string[];
|
|
36
|
+
slots?: AppRouteTreePrefetchRoute["slots"];
|
|
33
37
|
};
|
|
34
38
|
type AppRscRouteMatch<TRoute> = {
|
|
35
39
|
params: AppPageParams;
|
|
@@ -63,6 +67,7 @@ type DispatchMatchedPageOptions<TRoute> = {
|
|
|
63
67
|
staticParamsValidationParams?: AppPageParams;
|
|
64
68
|
rootParams?: RootParams;
|
|
65
69
|
request: Request;
|
|
70
|
+
renderedPathAndSearch?: string | null;
|
|
66
71
|
route: TRoute;
|
|
67
72
|
scriptNonce?: string;
|
|
68
73
|
searchParams: URLSearchParams;
|
|
@@ -189,6 +194,7 @@ type CreateAppRscHandlerOptions<TRoute extends AppRscHandlerRoute> = {
|
|
|
189
194
|
matchRoute: (pathname: string) => AppRscRouteMatch<TRoute> | null;
|
|
190
195
|
runMiddleware?: (options: RunAppMiddlewareOptions) => Promise<ApplyAppMiddlewareResult>;
|
|
191
196
|
publicFiles: ReadonlySet<string>;
|
|
197
|
+
prefetchInlining?: PrefetchInliningConfig;
|
|
192
198
|
renderNotFound: (options: RenderNotFoundOptions<TRoute>) => Promise<Response | null>;
|
|
193
199
|
renderPagesFallback?: (options: RenderPagesFallbackOptions) => Promise<Response | null>;
|
|
194
200
|
rootParamNamesByPattern?: RootParamNamesMap;
|