vinext 0.1.2 → 0.1.3

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.
Files changed (199) hide show
  1. package/dist/build/prerender.d.ts +9 -1
  2. package/dist/build/prerender.js +41 -12
  3. package/dist/build/run-prerender.d.ts +10 -2
  4. package/dist/build/run-prerender.js +15 -1
  5. package/dist/client/app-nav-failure-handler.d.ts +8 -0
  6. package/dist/client/app-nav-failure-handler.js +44 -0
  7. package/dist/client/vinext-next-data.d.ts +18 -1
  8. package/dist/client/window-next.d.ts +2 -1
  9. package/dist/client/window-next.js +12 -1
  10. package/dist/cloudflare/src/cache/cdn-adapter.runtime.js +6 -1
  11. package/dist/config/config-matchers.js +73 -14
  12. package/dist/config/next-config.d.ts +46 -4
  13. package/dist/config/next-config.js +147 -48
  14. package/dist/deploy.d.ts +30 -11
  15. package/dist/deploy.js +180 -99
  16. package/dist/entries/app-browser-entry.d.ts +9 -3
  17. package/dist/entries/app-browser-entry.js +21 -3
  18. package/dist/entries/app-rsc-entry.d.ts +2 -0
  19. package/dist/entries/app-rsc-entry.js +64 -5
  20. package/dist/entries/app-rsc-manifest.js +2 -0
  21. package/dist/entries/app-ssr-entry.js +1 -1
  22. package/dist/entries/pages-client-entry.js +53 -8
  23. package/dist/entries/pages-server-entry.js +41 -5
  24. package/dist/index.js +200 -62
  25. package/dist/plugins/extensionless-dynamic-import.d.ts +6 -0
  26. package/dist/plugins/extensionless-dynamic-import.js +152 -0
  27. package/dist/plugins/optimize-imports.d.ts +2 -1
  28. package/dist/plugins/optimize-imports.js +11 -9
  29. package/dist/plugins/postcss.js +7 -7
  30. package/dist/plugins/typeof-window.d.ts +14 -0
  31. package/dist/plugins/typeof-window.js +150 -0
  32. package/dist/routing/app-route-graph.d.ts +2 -1
  33. package/dist/routing/app-route-graph.js +44 -14
  34. package/dist/routing/file-matcher.d.ts +10 -1
  35. package/dist/routing/file-matcher.js +22 -1
  36. package/dist/routing/pages-router.js +3 -3
  37. package/dist/routing/utils.d.ts +35 -6
  38. package/dist/routing/utils.js +59 -7
  39. package/dist/server/api-handler.d.ts +6 -1
  40. package/dist/server/api-handler.js +21 -15
  41. package/dist/server/app-browser-action-result.d.ts +19 -6
  42. package/dist/server/app-browser-action-result.js +19 -10
  43. package/dist/server/app-browser-entry.js +167 -90
  44. package/dist/server/app-browser-error.d.ts +10 -6
  45. package/dist/server/app-browser-error.js +43 -8
  46. package/dist/server/app-browser-hydration.d.ts +2 -0
  47. package/dist/server/app-browser-hydration.js +1 -0
  48. package/dist/server/app-browser-navigation-controller.d.ts +4 -2
  49. package/dist/server/app-browser-navigation-controller.js +23 -2
  50. package/dist/server/app-browser-server-action-navigation.d.ts +6 -0
  51. package/dist/server/app-browser-server-action-navigation.js +9 -0
  52. package/dist/server/app-browser-stream.js +86 -43
  53. package/dist/server/app-elements-wire.d.ts +6 -1
  54. package/dist/server/app-elements-wire.js +14 -4
  55. package/dist/server/app-elements.d.ts +2 -2
  56. package/dist/server/app-elements.js +2 -2
  57. package/dist/server/app-fallback-renderer.d.ts +1 -0
  58. package/dist/server/app-fallback-renderer.js +3 -1
  59. package/dist/server/app-optimistic-routing.js +2 -2
  60. package/dist/server/app-page-boundary-render.d.ts +1 -0
  61. package/dist/server/app-page-boundary-render.js +27 -14
  62. package/dist/server/app-page-cache-render.d.ts +53 -0
  63. package/dist/server/app-page-cache-render.js +91 -0
  64. package/dist/server/app-page-cache.d.ts +16 -2
  65. package/dist/server/app-page-cache.js +62 -1
  66. package/dist/server/app-page-dispatch.d.ts +26 -0
  67. package/dist/server/app-page-dispatch.js +149 -92
  68. package/dist/server/app-page-element-builder.d.ts +1 -0
  69. package/dist/server/app-page-element-builder.js +5 -2
  70. package/dist/server/app-page-execution.d.ts +6 -1
  71. package/dist/server/app-page-execution.js +21 -1
  72. package/dist/server/app-page-probe.d.ts +1 -0
  73. package/dist/server/app-page-probe.js +4 -0
  74. package/dist/server/app-page-render-observation.d.ts +3 -1
  75. package/dist/server/app-page-render-observation.js +17 -1
  76. package/dist/server/app-page-render.d.ts +12 -1
  77. package/dist/server/app-page-render.js +42 -4
  78. package/dist/server/app-page-request.d.ts +2 -0
  79. package/dist/server/app-page-request.js +2 -1
  80. package/dist/server/app-page-route-wiring.d.ts +3 -1
  81. package/dist/server/app-page-route-wiring.js +14 -5
  82. package/dist/server/app-page-stream.d.ts +15 -3
  83. package/dist/server/app-page-stream.js +11 -5
  84. package/dist/server/app-pages-bridge.d.ts +18 -0
  85. package/dist/server/app-pages-bridge.js +22 -5
  86. package/dist/server/app-ppr-fallback-shell-render.d.ts +17 -0
  87. package/dist/server/app-ppr-fallback-shell-render.js +26 -0
  88. package/dist/server/app-ppr-fallback-shell.d.ts +13 -1
  89. package/dist/server/app-ppr-fallback-shell.js +8 -1
  90. package/dist/server/app-route-handler-dispatch.js +9 -2
  91. package/dist/server/app-route-handler-policy.d.ts +1 -0
  92. package/dist/server/app-router-entry.js +5 -0
  93. package/dist/server/app-rsc-cache-busting.js +2 -0
  94. package/dist/server/app-rsc-handler.d.ts +25 -0
  95. package/dist/server/app-rsc-handler.js +154 -54
  96. package/dist/server/app-rsc-route-matching.d.ts +3 -0
  97. package/dist/server/app-rsc-route-matching.js +2 -0
  98. package/dist/server/app-segment-config.d.ts +9 -1
  99. package/dist/server/app-segment-config.js +12 -3
  100. package/dist/server/app-server-action-execution.d.ts +1 -0
  101. package/dist/server/app-server-action-execution.js +42 -13
  102. package/dist/server/app-ssr-entry.d.ts +2 -0
  103. package/dist/server/app-ssr-entry.js +83 -10
  104. package/dist/server/cache-control.js +4 -0
  105. package/dist/server/dev-server.d.ts +2 -2
  106. package/dist/server/dev-server.js +244 -51
  107. package/dist/server/hybrid-route-priority.d.ts +22 -0
  108. package/dist/server/hybrid-route-priority.js +33 -0
  109. package/dist/server/image-optimization.d.ts +18 -9
  110. package/dist/server/image-optimization.js +37 -23
  111. package/dist/server/implicit-tags.d.ts +2 -1
  112. package/dist/server/implicit-tags.js +4 -1
  113. package/dist/server/navigation-planner.d.ts +133 -30
  114. package/dist/server/navigation-planner.js +114 -0
  115. package/dist/server/navigation-trace.d.ts +8 -1
  116. package/dist/server/navigation-trace.js +8 -1
  117. package/dist/server/pages-api-route.d.ts +6 -0
  118. package/dist/server/pages-api-route.js +13 -2
  119. package/dist/server/pages-asset-tags.d.ts +2 -1
  120. package/dist/server/pages-asset-tags.js +6 -2
  121. package/dist/server/pages-data-route.d.ts +8 -1
  122. package/dist/server/pages-data-route.js +11 -2
  123. package/dist/server/pages-get-initial-props.d.ts +54 -4
  124. package/dist/server/pages-get-initial-props.js +43 -1
  125. package/dist/server/pages-node-compat.js +2 -2
  126. package/dist/server/pages-page-data.d.ts +11 -2
  127. package/dist/server/pages-page-data.js +204 -33
  128. package/dist/server/pages-page-handler.d.ts +4 -2
  129. package/dist/server/pages-page-handler.js +59 -22
  130. package/dist/server/pages-page-response.d.ts +2 -1
  131. package/dist/server/pages-page-response.js +7 -4
  132. package/dist/server/pages-request-pipeline.d.ts +1 -0
  133. package/dist/server/pages-request-pipeline.js +73 -36
  134. package/dist/server/pregenerated-concrete-paths.d.ts +1 -17
  135. package/dist/server/pregenerated-concrete-paths.js +2 -19
  136. package/dist/server/prerender-manifest.d.ts +33 -0
  137. package/dist/server/prerender-manifest.js +54 -0
  138. package/dist/server/prerender-route-params.d.ts +1 -2
  139. package/dist/server/prod-server.js +9 -3
  140. package/dist/server/request-pipeline.d.ts +3 -15
  141. package/dist/server/request-pipeline.js +58 -47
  142. package/dist/server/rsc-stream-hints.d.ts +5 -1
  143. package/dist/server/rsc-stream-hints.js +6 -1
  144. package/dist/server/seed-cache.js +10 -18
  145. package/dist/shims/app-router-scroll-state.d.ts +3 -1
  146. package/dist/shims/app-router-scroll-state.js +14 -2
  147. package/dist/shims/app-router-scroll.d.ts +3 -0
  148. package/dist/shims/app-router-scroll.js +28 -18
  149. package/dist/shims/cache-runtime.js +3 -2
  150. package/dist/shims/cache.d.ts +1 -0
  151. package/dist/shims/cache.js +1 -1
  152. package/dist/shims/cdn-cache.d.ts +5 -5
  153. package/dist/shims/dynamic-preload-chunks.js +6 -4
  154. package/dist/shims/error-boundary.d.ts +2 -0
  155. package/dist/shims/error-boundary.js +7 -0
  156. package/dist/shims/error.js +3 -2
  157. package/dist/shims/error.react-server.d.ts +9 -0
  158. package/dist/shims/error.react-server.js +6 -0
  159. package/dist/shims/fetch-cache.d.ts +3 -1
  160. package/dist/shims/fetch-cache.js +45 -20
  161. package/dist/shims/hash-scroll.js +6 -1
  162. package/dist/shims/headers.js +29 -4
  163. package/dist/shims/internal/als-registry.js +28 -1
  164. package/dist/shims/internal/app-route-detection.js +8 -17
  165. package/dist/shims/internal/hybrid-client-route-owner.d.ts +31 -0
  166. package/dist/shims/internal/hybrid-client-route-owner.js +143 -0
  167. package/dist/shims/internal/navigation-untracked.d.ts +35 -0
  168. package/dist/shims/internal/navigation-untracked.js +55 -0
  169. package/dist/shims/internal/pages-data-target.d.ts +7 -2
  170. package/dist/shims/internal/pages-data-target.js +17 -8
  171. package/dist/shims/internal/pages-router-accessor.d.ts +19 -0
  172. package/dist/shims/internal/pages-router-accessor.js +13 -0
  173. package/dist/shims/internal/router-context.d.ts +2 -1
  174. package/dist/shims/internal/router-context.js +3 -1
  175. package/dist/shims/link.js +12 -5
  176. package/dist/shims/navigation.d.ts +8 -2
  177. package/dist/shims/navigation.js +61 -31
  178. package/dist/shims/ppr-fallback-shell.d.ts +5 -1
  179. package/dist/shims/ppr-fallback-shell.js +28 -7
  180. package/dist/shims/router.d.ts +13 -2
  181. package/dist/shims/router.js +419 -128
  182. package/dist/shims/server.d.ts +16 -1
  183. package/dist/shims/server.js +44 -12
  184. package/dist/shims/unified-request-context.js +1 -0
  185. package/dist/utils/built-asset-url.d.ts +4 -0
  186. package/dist/utils/built-asset-url.js +11 -0
  187. package/dist/utils/commonjs-loader.d.ts +16 -0
  188. package/dist/utils/commonjs-loader.js +100 -0
  189. package/dist/utils/deployment-id.d.ts +8 -0
  190. package/dist/utils/deployment-id.js +22 -0
  191. package/dist/utils/html-limited-bots.d.ts +18 -1
  192. package/dist/utils/html-limited-bots.js +23 -1
  193. package/dist/utils/parse-cookie.d.ts +13 -0
  194. package/dist/utils/parse-cookie.js +52 -0
  195. package/dist/utils/path.d.ts +7 -1
  196. package/dist/utils/path.js +9 -1
  197. package/package.json +2 -2
  198. package/dist/shims/internal/parse-cookie-header.d.ts +0 -14
  199. package/dist/shims/internal/parse-cookie-header.js +0 -30
@@ -30,7 +30,7 @@ declare function getManifestFilesForModule(manifest: Record<string, string[]> |
30
30
  * asset URLs. SSR-manifest values are base-anchored; re-anchor under any
31
31
  * configured `assetPrefix` (default `""` keeps the legacy `"/" + file`).
32
32
  */
33
- declare function resolveClientModuleUrl(manifest: Record<string, string[]> | null | undefined, moduleId: string | null | undefined, basePath?: string, assetPrefix?: string): string | undefined;
33
+ declare function resolveClientModuleUrl(manifest: Record<string, string[]> | null | undefined, moduleId: string | null | undefined, basePath?: string, assetPrefix?: string, _deploymentId?: string): string | undefined;
34
34
  type CollectAssetTagsOptions = {
35
35
  /**
36
36
  * SSR manifest mapping module file paths to their associated asset list.
@@ -57,6 +57,7 @@ type CollectAssetTagsOptions = {
57
57
  */
58
58
  basePath?: string;
59
59
  assetPrefix?: string;
60
+ deploymentId?: string;
60
61
  };
61
62
  /**
62
63
  * Build the HTML `<link>` and `<script>` tag string for the SSR response.
@@ -1,3 +1,4 @@
1
+ import { appendDeploymentIdQuery } from "../utils/deployment-id.js";
1
2
  import { createNonceAttribute } from "./html.js";
2
3
  import { assetServingUrlFromBaseAnchored } from "../utils/manifest-paths.js";
3
4
  //#region src/server/pages-asset-tags.ts
@@ -41,7 +42,7 @@ function getManifestFilesForModule(manifest, moduleId) {
41
42
  * asset URLs. SSR-manifest values are base-anchored; re-anchor under any
42
43
  * configured `assetPrefix` (default `""` keeps the legacy `"/" + file`).
43
44
  */
44
- function resolveClientModuleUrl(manifest, moduleId, basePath = "", assetPrefix = "") {
45
+ function resolveClientModuleUrl(manifest, moduleId, basePath = "", assetPrefix = "", _deploymentId) {
45
46
  const files = getManifestFilesForModule(resolveSsrManifest(manifest), moduleId);
46
47
  if (!files) return void 0;
47
48
  for (let i = 0; i < files.length; i++) {
@@ -72,7 +73,10 @@ function collectAssetTags(options) {
72
73
  const deferAttr = options.disableOptimizedLoading ? "" : " defer";
73
74
  const basePath = options.basePath ?? "";
74
75
  const assetPrefix = options.assetPrefix ?? "";
75
- const href = (value) => assetServingUrlFromBaseAnchored(value, basePath, assetPrefix);
76
+ const href = (value) => {
77
+ const url = assetServingUrlFromBaseAnchored(value, basePath, assetPrefix);
78
+ return value.endsWith(".js") ? url : appendDeploymentIdQuery(url, options.deploymentId);
79
+ };
76
80
  const lazyChunks = typeof globalThis !== "undefined" && globalThis.__VINEXT_LAZY_CHUNKS__ || null;
77
81
  const lazySet = lazyChunks && lazyChunks.length > 0 ? new Set(lazyChunks) : null;
78
82
  if (typeof globalThis !== "undefined" && globalThis.__VINEXT_CLIENT_ENTRY__) {
@@ -60,6 +60,13 @@ declare function parseNextDataPathname(pathname: string, buildId: string): NextD
60
60
  * { pageProps: {...}, /* optional locale data, redirect markers, etc. *\/ }
61
61
  */
62
62
  declare function buildNextDataJsonResponse(pageProps: Record<string, unknown>, safeJsonStringify: (value: unknown) => string, init?: ResponseInit): Response;
63
+ /**
64
+ * Build a `_next/data` JSON response from the full Pages props object returned
65
+ * through `_app.getInitialProps`. Next.js serializes the same outer props
66
+ * object that would be passed to `<App />`, so custom app-level props remain
67
+ * siblings of `pageProps` in the data envelope.
68
+ */
69
+ declare function buildNextDataPropsJsonResponse(props: Record<string, unknown>, safeJsonStringify: (value: unknown) => string, init?: ResponseInit): Response;
63
70
  /**
64
71
  * Build the 404 response Next.js returns for an unknown `_next/data` page.
65
72
  * Next.js renders this as a normal 404 page, but the body shape that clients
@@ -111,4 +118,4 @@ type NormalizePagesDataRequestResult = {
111
118
  */
112
119
  declare function normalizePagesDataRequest(request: Request, buildId: string | null): NormalizePagesDataRequestResult;
113
120
  //#endregion
114
- export { buildNextDataJsonResponse, buildNextDataNotFoundResponse, isNextDataPathname, normalizePagesDataRequest, parseNextDataPathname };
121
+ export { buildNextDataJsonResponse, buildNextDataNotFoundResponse, buildNextDataPropsJsonResponse, isNextDataPathname, normalizePagesDataRequest, parseNextDataPathname };
@@ -66,7 +66,16 @@ function parseNextDataPathname(pathname, buildId) {
66
66
  * { pageProps: {...}, /* optional locale data, redirect markers, etc. *\/ }
67
67
  */
68
68
  function buildNextDataJsonResponse(pageProps, safeJsonStringify, init) {
69
- const body = safeJsonStringify({ pageProps });
69
+ return buildNextDataPropsJsonResponse({ pageProps }, safeJsonStringify, init);
70
+ }
71
+ /**
72
+ * Build a `_next/data` JSON response from the full Pages props object returned
73
+ * through `_app.getInitialProps`. Next.js serializes the same outer props
74
+ * object that would be passed to `<App />`, so custom app-level props remain
75
+ * siblings of `pageProps` in the data envelope.
76
+ */
77
+ function buildNextDataPropsJsonResponse(props, safeJsonStringify, init) {
78
+ const body = safeJsonStringify(props);
70
79
  return new Response(body, {
71
80
  status: init?.status ?? 200,
72
81
  statusText: init?.statusText,
@@ -142,4 +151,4 @@ function normalizePagesDataRequest(request, buildId) {
142
151
  };
143
152
  }
144
153
  //#endregion
145
- export { buildNextDataJsonResponse, buildNextDataNotFoundResponse, isNextDataPathname, normalizePagesDataRequest, parseNextDataPathname };
154
+ export { buildNextDataJsonResponse, buildNextDataNotFoundResponse, buildNextDataPropsJsonResponse, isNextDataPathname, normalizePagesDataRequest, parseNextDataPathname };
@@ -3,6 +3,48 @@ type PagesGetInitialPropsContext = {
3
3
  req?: unknown;
4
4
  res?: unknown;
5
5
  err?: unknown;
6
+ pathname?: string;
7
+ query?: Record<string, unknown>;
8
+ asPath?: string;
9
+ locale?: string;
10
+ locales?: string[];
11
+ defaultLocale?: string;
12
+ } & Record<string, unknown>;
13
+ declare function hasPagesGetInitialProps(component: unknown): boolean;
14
+ declare function isResponseSent(res: unknown): boolean;
15
+ declare function loadPagesGetInitialProps(component: unknown, context: PagesGetInitialPropsContext): Promise<Record<string, unknown> | null>;
16
+ /**
17
+ * Decision returned by {@link loadDevAppInitialProps}.
18
+ *
19
+ * - `skip`: the custom `App` has no `getInitialProps`; the caller renders with
20
+ * its existing props unchanged.
21
+ * - `response-sent`: `_app.getInitialProps` ended the response itself (wrote
22
+ * headers / body); the caller must stop and not render.
23
+ * - `render`: the caller should render with the returned `pageProps` /
24
+ * `renderProps`.
25
+ */
26
+ type DevAppInitialPropsResult = {
27
+ kind: "skip";
28
+ } | {
29
+ kind: "response-sent";
30
+ } | {
31
+ kind: "render";
32
+ pageProps: Record<string, unknown>;
33
+ renderProps: Record<string, unknown> & {
34
+ pageProps: unknown;
35
+ };
36
+ };
37
+ type DevAppInitialPropsContext = {
38
+ appComponent: unknown;
39
+ /**
40
+ * Builds the `AppTree` element passed to `getInitialProps`. Injected so this
41
+ * module stays free of React; the dev SSR handler supplies the real
42
+ * `React.createElement` closure.
43
+ */
44
+ appTree: (appTreeProps: Record<string, unknown>) => unknown;
45
+ component: unknown;
46
+ req: unknown;
47
+ res: unknown;
6
48
  pathname: string;
7
49
  query: Record<string, unknown>;
8
50
  asPath: string;
@@ -10,8 +52,16 @@ type PagesGetInitialPropsContext = {
10
52
  locales?: string[];
11
53
  defaultLocale?: string;
12
54
  };
13
- declare function hasPagesGetInitialProps(component: unknown): boolean;
14
- declare function isResponseSent(res: unknown): boolean;
15
- declare function loadPagesGetInitialProps(component: unknown, context: PagesGetInitialPropsContext): Promise<Record<string, unknown> | null>;
55
+ /**
56
+ * Run the custom `App`'s `getInitialProps` for the dev SSR render path and
57
+ * return a decision the caller applies.
58
+ *
59
+ * This is the dev-server counterpart to the production page-data resolver's
60
+ * app-initial-props loading. It is invoked lazily — only when a request is
61
+ * actually going to render (cache miss / on-demand revalidation), never on an
62
+ * ISR cache HIT/STALE that serves cached HTML verbatim — so userland `App`
63
+ * data code does not run on the cache hot path.
64
+ */
65
+ declare function loadDevAppInitialProps(ctx: DevAppInitialPropsContext): Promise<DevAppInitialPropsResult>;
16
66
  //#endregion
17
- export { hasPagesGetInitialProps, isResponseSent, loadPagesGetInitialProps };
67
+ export { DevAppInitialPropsContext, DevAppInitialPropsResult, hasPagesGetInitialProps, isResponseSent, loadDevAppInitialProps, loadPagesGetInitialProps };
@@ -46,5 +46,47 @@ async function loadPagesGetInitialProps(component, context) {
46
46
  if (!isPropsObject(result)) throw new Error(`"${getDisplayName(component)}.getInitialProps()" should resolve to an object. But found "${describeInitialPropsValue(result)}" instead.`);
47
47
  return result;
48
48
  }
49
+ /**
50
+ * Run the custom `App`'s `getInitialProps` for the dev SSR render path and
51
+ * return a decision the caller applies.
52
+ *
53
+ * This is the dev-server counterpart to the production page-data resolver's
54
+ * app-initial-props loading. It is invoked lazily — only when a request is
55
+ * actually going to render (cache miss / on-demand revalidation), never on an
56
+ * ISR cache HIT/STALE that serves cached HTML verbatim — so userland `App`
57
+ * data code does not run on the cache hot path.
58
+ */
59
+ async function loadDevAppInitialProps(ctx) {
60
+ if (!hasPagesGetInitialProps(ctx.appComponent)) return { kind: "skip" };
61
+ const initialProps = await loadPagesGetInitialProps(ctx.appComponent, {
62
+ AppTree: ctx.appTree,
63
+ Component: ctx.component,
64
+ router: {
65
+ pathname: ctx.pathname,
66
+ query: ctx.query,
67
+ asPath: ctx.asPath
68
+ },
69
+ ctx: {
70
+ req: ctx.req,
71
+ res: ctx.res,
72
+ pathname: ctx.pathname,
73
+ query: ctx.query,
74
+ asPath: ctx.asPath,
75
+ locale: ctx.locale,
76
+ locales: ctx.locales,
77
+ defaultLocale: ctx.defaultLocale
78
+ }
79
+ });
80
+ if (isResponseSent(ctx.res)) return { kind: "response-sent" };
81
+ const initialPageProps = isPropsObject(initialProps) ? initialProps.pageProps : void 0;
82
+ return {
83
+ kind: "render",
84
+ pageProps: isPropsObject(initialPageProps) ? initialPageProps : {},
85
+ renderProps: isPropsObject(initialProps) ? {
86
+ ...initialProps,
87
+ pageProps: initialPageProps
88
+ } : { pageProps: initialPageProps }
89
+ };
90
+ }
49
91
  //#endregion
50
- export { hasPagesGetInitialProps, isResponseSent, loadPagesGetInitialProps };
92
+ export { hasPagesGetInitialProps, isResponseSent, loadDevAppInitialProps, loadPagesGetInitialProps };
@@ -1,4 +1,4 @@
1
- import { parseCookies } from "../config/config-matchers.js";
1
+ import { parseCookieHeader } from "../utils/parse-cookie.js";
2
2
  import { readStreamAsTextWithLimit } from "../utils/text-stream.js";
3
3
  import { PagesBodyParseError, getMediaType, isJsonMediaType } from "./pages-media-type.js";
4
4
  import { DEFAULT_PAGES_API_BODY_SIZE_LIMIT } from "./pages-body-parser-config.js";
@@ -217,7 +217,7 @@ function createPagesReqRes(options) {
217
217
  headers: headersObj,
218
218
  query: options.query,
219
219
  body: options.body,
220
- cookies: parseCookies(options.request.headers.get("cookie"))
220
+ cookies: parseCookieHeader(options.request.headers.get("cookie"))
221
221
  });
222
222
  let resolveResponse;
223
223
  let rejectResponse;
@@ -33,6 +33,9 @@ type PagesGsspContextResponse = {
33
33
  res: PagesMutableGsspResponse;
34
34
  responsePromise: Promise<Response>;
35
35
  };
36
+ type PagesRenderProps = Record<string, unknown> & {
37
+ pageProps: unknown;
38
+ };
36
39
  type PagesPageModule = {
37
40
  default?: unknown;
38
41
  getStaticPaths?: (context: {
@@ -82,9 +85,10 @@ type PagesPageModule = {
82
85
  type RenderPagesIsrHtmlOptions = {
83
86
  buildId: string | null;
84
87
  cachedHtml: string;
85
- createPageElement: (pageProps: Record<string, unknown>) => ReactNode;
88
+ createPageElement: (props: Record<string, unknown>) => ReactNode;
86
89
  i18n: PagesI18nRenderContext;
87
90
  pageProps: Record<string, unknown>;
91
+ props?: Record<string, unknown>;
88
92
  params: Record<string, unknown>;
89
93
  renderIsrPassToStringAsync: (element: ReactNode) => Promise<string>;
90
94
  routePattern: string;
@@ -106,7 +110,8 @@ type ResolvePagesPageDataOptions = {
106
110
  isDataReq?: boolean;
107
111
  err?: unknown;
108
112
  createGsspReqRes: () => PagesGsspContextResponse;
109
- createPageElement: (pageProps: Record<string, unknown>) => ReactNode;
113
+ createAppTree?: (props: Record<string, unknown>) => ReactNode;
114
+ createPageElement: (props: Record<string, unknown>) => ReactNode;
110
115
  fontLinkHeader: string;
111
116
  i18n: PagesI18nRenderContext;
112
117
  isrCacheKey: (router: string, pathname: string) => string;
@@ -145,10 +150,13 @@ type ResolvePagesPageDataOptions = {
145
150
  * Typically sourced from `process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID`.
146
151
  */
147
152
  deploymentId?: string;
153
+ htmlLimitedBots?: string;
148
154
  pageModule: PagesPageModule;
155
+ AppComponent?: unknown;
149
156
  params: Record<string, unknown>;
150
157
  query: Record<string, unknown>;
151
158
  asPath?: string;
159
+ resolvedUrl?: string;
152
160
  route: Pick<Route, "isDynamic">;
153
161
  routePattern: string;
154
162
  routeUrl: string;
@@ -192,6 +200,7 @@ type ResolvePagesPageDataRenderResult = {
192
200
  gsspRes: PagesGsspResponse | null;
193
201
  isrRevalidateSeconds: number | null;
194
202
  pageProps: Record<string, unknown>;
203
+ props: PagesRenderProps;
195
204
  /**
196
205
  * True when `getStaticPaths` returned `fallback: true` AND the requested path
197
206
  * is not in the pre-rendered list. The caller renders a loading shell with
@@ -1,12 +1,14 @@
1
1
  import { NEXTJS_DEPLOYMENT_ID_HEADER } from "./headers.js";
2
2
  import { normalizeStaticPathname } from "../routing/route-pattern.js";
3
3
  import { buildCacheStateHeaders } from "./cache-headers.js";
4
+ import { isUnknownRecord } from "../utils/record.js";
4
5
  import { applyCdnResponseHeaders } from "./cache-control.js";
5
6
  import { decideIsr } from "./isr-decision.js";
6
7
  import { buildPagesCacheValue } from "./isr-cache.js";
7
8
  import { isSerializableProps } from "./pages-serializable-props.js";
8
9
  import { hasPagesGetInitialProps, isResponseSent, loadPagesGetInitialProps } from "./pages-get-initial-props.js";
9
- import { buildNextDataJsonResponse } from "./pages-data-route.js";
10
+ import { isBotUserAgent } from "../utils/html-limited-bots.js";
11
+ import { buildNextDataPropsJsonResponse } from "./pages-data-route.js";
10
12
  import { buildPagesNextDataScript, etagMatches, generatePagesETag, isPagesStreamingBot, requestsNoCache } from "./pages-page-response.js";
11
13
  //#region src/server/pages-page-data.ts
12
14
  function buildPagesDataNotFoundResponse(deploymentId) {
@@ -27,6 +29,65 @@ function buildPagesNotFoundResult(options) {
27
29
  function resolvePagesRedirectStatus(redirect) {
28
30
  return redirect.statusCode != null ? redirect.statusCode : redirect.permanent ? 308 : 307;
29
31
  }
32
+ function normalizePagesRenderProps(props) {
33
+ return {
34
+ ...props,
35
+ pageProps: props.pageProps
36
+ };
37
+ }
38
+ /**
39
+ * Load `_app.getInitialProps` and return the normalized render props and the
40
+ * extracted `pageProps`. This is shared between the foreground render path and
41
+ * the stale-while-revalidate background regeneration path so both produce the
42
+ * same full props envelope (app-level props plus the page's `pageProps`).
43
+ *
44
+ * `getSharedReqRes` lets callers share the same mock req/res with other
45
+ * data-fetching steps (e.g. `getServerSideProps`) when they run in the same
46
+ * request context.
47
+ */
48
+ async function loadPagesAppInitialRenderProps(options, getSharedReqRes) {
49
+ let pageProps = {};
50
+ let renderProps = { pageProps };
51
+ if (!hasPagesGetInitialProps(options.AppComponent)) return {
52
+ kind: "props",
53
+ pageProps,
54
+ renderProps
55
+ };
56
+ const { req, res, responsePromise } = getSharedReqRes();
57
+ const initialProps = await loadPagesGetInitialProps(options.AppComponent, {
58
+ AppTree: options.createAppTree ?? options.createPageElement,
59
+ Component: options.pageModule.default,
60
+ router: {
61
+ pathname: options.routePattern,
62
+ query: options.query,
63
+ asPath: options.asPath ?? options.routeUrl
64
+ },
65
+ ctx: {
66
+ req,
67
+ res,
68
+ err: options.err,
69
+ pathname: options.routePattern,
70
+ query: options.query,
71
+ asPath: options.asPath ?? options.routeUrl,
72
+ locale: options.i18n.locale,
73
+ locales: options.i18n.locales,
74
+ defaultLocale: options.i18n.defaultLocale
75
+ }
76
+ });
77
+ if (isResponseSent(res)) return {
78
+ kind: "response",
79
+ response: responsePromise
80
+ };
81
+ if (initialProps) {
82
+ renderProps = normalizePagesRenderProps(initialProps);
83
+ pageProps = isUnknownRecord(renderProps.pageProps) ? renderProps.pageProps : {};
84
+ }
85
+ return {
86
+ kind: "props",
87
+ pageProps,
88
+ renderProps
89
+ };
90
+ }
30
91
  /**
31
92
  * Build the response for a `getServerSideProps` / `getStaticProps`
32
93
  * `{ redirect }` result.
@@ -48,14 +109,18 @@ function resolvePagesRedirectStatus(redirect) {
48
109
  * redirects (search `__N_REDIRECT`), consumed in
49
110
  * `packages/next/src/shared/lib/router/router.ts` (`pageProps.__N_REDIRECT`).
50
111
  */
51
- function buildPagesRedirectResponse(redirect, options) {
112
+ function buildPagesRedirectResponse(redirect, options, props = { pageProps: {} }) {
52
113
  const destination = options.sanitizeDestination(redirect.destination);
53
114
  if (options.isDataReq) {
54
115
  const init = { headers: {} };
55
116
  if (options.deploymentId) init.headers[NEXTJS_DEPLOYMENT_ID_HEADER] = options.deploymentId;
56
- return buildNextDataJsonResponse({
57
- __N_REDIRECT: destination,
58
- __N_REDIRECT_STATUS: resolvePagesRedirectStatus(redirect)
117
+ return buildNextDataPropsJsonResponse({
118
+ ...props,
119
+ pageProps: {
120
+ ...isUnknownRecord(props.pageProps) ? props.pageProps : {},
121
+ __N_REDIRECT: destination,
122
+ __N_REDIRECT_STATUS: resolvePagesRedirectStatus(redirect)
123
+ }
59
124
  }, options.safeJsonStringify, init);
60
125
  }
61
126
  return new Response(null, {
@@ -145,11 +210,13 @@ function rewritePagesCachedHtml(cachedHtml, freshBody, nextDataScript) {
145
210
  return "<!DOCTYPE html>\n<html>\n<head>\n</head>\n<body>\n <div id=\"__next\">" + freshBody + "</div>\n " + nextDataScript + "\n</body>\n</html>";
146
211
  }
147
212
  async function renderPagesIsrHtml(options) {
148
- const freshBody = await options.renderIsrPassToStringAsync(options.createPageElement(options.pageProps));
213
+ const renderProps = options.props ?? { pageProps: options.pageProps };
214
+ const freshBody = await options.renderIsrPassToStringAsync(options.createPageElement(renderProps));
149
215
  const nextDataScript = buildPagesNextDataScript({
150
216
  buildId: options.buildId,
151
217
  i18n: options.i18n,
152
218
  pageProps: options.pageProps,
219
+ props: renderProps,
153
220
  params: options.params,
154
221
  routePattern: options.routePattern,
155
222
  safeJsonStringify: options.safeJsonStringify,
@@ -161,6 +228,7 @@ async function renderPagesIsrHtml(options) {
161
228
  async function resolvePagesPageData(options) {
162
229
  const userFacingParams = options.route.isDynamic ? options.params : null;
163
230
  let isFallback = false;
231
+ let shouldPersistFallbackData = false;
164
232
  if (typeof options.pageModule.getStaticPaths === "function" && options.route.isDynamic) {
165
233
  const pathsResult = await options.pageModule.getStaticPaths({
166
234
  locales: options.i18n.locales ?? [],
@@ -169,25 +237,62 @@ async function resolvePagesPageData(options) {
169
237
  const fallback = pathsResult?.fallback ?? false;
170
238
  const isValidPath = (pathsResult?.paths ?? []).some((pathEntry) => matchesPagesStaticPath(pathEntry, options.params, options.routeUrl));
171
239
  if (fallback === false && !isValidPath) return buildPagesNotFoundResult(options);
172
- if (fallback === true && !isValidPath && !options.isDataReq) isFallback = true;
240
+ const isBotRequest = !!options.userAgent && isBotUserAgent(options.userAgent, options.htmlLimitedBots);
241
+ if (fallback === true && !isValidPath && !options.isDataReq && !isBotRequest) isFallback = true;
242
+ shouldPersistFallbackData = fallback === true && !isValidPath && options.isDataReq === true;
173
243
  }
174
244
  let pageProps = {};
175
245
  let gsspRes = null;
176
- if (isFallback) return {
177
- kind: "render",
178
- gsspRes: null,
179
- isrRevalidateSeconds: null,
180
- pageProps,
181
- isFallback: true
182
- };
246
+ let sharedReqRes = null;
247
+ function getSharedReqRes() {
248
+ sharedReqRes ??= options.createGsspReqRes();
249
+ return sharedReqRes;
250
+ }
251
+ let renderProps = { pageProps };
252
+ async function loadForegroundAppInitialRenderProps() {
253
+ const result = await loadPagesAppInitialRenderProps(options, getSharedReqRes);
254
+ if (result.kind === "response") return {
255
+ kind: "response",
256
+ response: await result.response
257
+ };
258
+ renderProps = result.renderProps;
259
+ pageProps = result.pageProps;
260
+ return null;
261
+ }
262
+ if (isFallback) {
263
+ const pathname = options.routeUrl.split("?")[0];
264
+ if ((await options.isrGet(options.isrCacheKey("pages", pathname)))?.value.value?.kind !== "PAGES") {
265
+ const appShortCircuit = await loadForegroundAppInitialRenderProps();
266
+ if (appShortCircuit) return appShortCircuit;
267
+ pageProps = {};
268
+ renderProps = {
269
+ ...renderProps,
270
+ pageProps
271
+ };
272
+ return {
273
+ kind: "render",
274
+ gsspRes: null,
275
+ isrRevalidateSeconds: null,
276
+ pageProps,
277
+ props: renderProps,
278
+ isFallback: true
279
+ };
280
+ }
281
+ }
183
282
  if (typeof options.pageModule.getServerSideProps === "function") {
184
- const { req, res, responsePromise } = options.createGsspReqRes();
283
+ const shortCircuit = await loadForegroundAppInitialRenderProps();
284
+ if (shortCircuit) return shortCircuit;
285
+ renderProps = {
286
+ ...renderProps,
287
+ __N_SSP: true
288
+ };
289
+ const { req, res, responsePromise } = getSharedReqRes();
185
290
  const result = await options.pageModule.getServerSideProps({
186
291
  params: userFacingParams,
187
292
  req,
188
293
  res,
189
294
  query: options.query,
190
- resolvedUrl: options.routeUrl,
295
+ resolvedUrl: options.resolvedUrl ?? options.routeUrl,
191
296
  locale: options.i18n.locale,
192
297
  locales: options.i18n.locales,
193
298
  defaultLocale: options.i18n.defaultLocale
@@ -196,10 +301,19 @@ async function resolvePagesPageData(options) {
196
301
  kind: "response",
197
302
  response: await responsePromise
198
303
  };
199
- if (result?.props) pageProps = await Promise.resolve(result.props);
304
+ if (result?.props) {
305
+ pageProps = {
306
+ ...pageProps,
307
+ ...await Promise.resolve(result.props)
308
+ };
309
+ renderProps = {
310
+ ...renderProps,
311
+ pageProps
312
+ };
313
+ }
200
314
  if (result?.redirect) return {
201
315
  kind: "response",
202
- response: buildPagesRedirectResponse(result.redirect, options)
316
+ response: buildPagesRedirectResponse(result.redirect, options, renderProps)
203
317
  };
204
318
  if (result?.notFound) return buildPagesNotFoundResult(options);
205
319
  if (result?.props !== void 0) isSerializableProps(options.routePattern, "getServerSideProps", pageProps);
@@ -211,7 +325,7 @@ async function resolvePagesPageData(options) {
211
325
  const cacheKey = options.isrCacheKey("pages", pathname);
212
326
  const cached = await options.isrGet(cacheKey);
213
327
  const cachedValue = cached?.value.value;
214
- if (!options.isOnDemandRevalidate && cachedValue?.kind === "PAGES" && cached && !cached.isStale && !options.scriptNonce && !options.isDataReq) {
328
+ if (!options.isOnDemandRevalidate && cached?.isStale === false && cachedValue?.kind === "PAGES" && !cachedValue.generatedFromDataRequest && cached && !cached.isStale && !options.scriptNonce && !options.isDataReq) {
215
329
  const hitResponse = buildPagesCacheResponse(cachedValue.html, "HIT", options.fontLinkHeader, void 0, options.expireSeconds, cached.value.cacheControl, cachedValue.status);
216
330
  const hitBotResult = applyBotETagAndCheck(hitResponse, cachedValue.html, options);
217
331
  if (hitBotResult) return hitBotResult;
@@ -220,9 +334,14 @@ async function resolvePagesPageData(options) {
220
334
  response: hitResponse
221
335
  };
222
336
  }
223
- if (!options.isOnDemandRevalidate && cachedValue?.kind === "PAGES" && cached && cached.isStale && !options.scriptNonce && !options.isDataReq) {
337
+ if (!options.isOnDemandRevalidate && cachedValue?.kind === "PAGES" && !cachedValue.generatedFromDataRequest && cached && cached.isStale && !options.scriptNonce && !options.isDataReq) {
224
338
  options.triggerBackgroundRegeneration(cacheKey, async function() {
225
339
  return options.runInFreshUnifiedContext(async () => {
340
+ options.applyRequestContexts();
341
+ const freshAppResult = await loadPagesAppInitialRenderProps(options, () => options.createGsspReqRes());
342
+ if (freshAppResult.kind === "response") return;
343
+ let freshPageProps = freshAppResult.pageProps;
344
+ let freshRenderProps = freshAppResult.renderProps;
226
345
  const freshResult = await options.pageModule.getStaticProps?.({
227
346
  params: userFacingParams,
228
347
  locale: options.i18n.locale,
@@ -230,14 +349,25 @@ async function resolvePagesPageData(options) {
230
349
  defaultLocale: options.i18n.defaultLocale,
231
350
  revalidateReason: "stale"
232
351
  });
233
- if (freshResult?.props && typeof freshResult.revalidate === "number" && freshResult.revalidate > 0) {
234
- options.applyRequestContexts();
352
+ if (freshResult?.props) {
353
+ freshPageProps = {
354
+ ...freshPageProps,
355
+ ...freshResult.props
356
+ };
357
+ freshRenderProps = {
358
+ ...freshRenderProps,
359
+ pageProps: freshPageProps
360
+ };
361
+ }
362
+ const freshRevalidateSeconds = typeof freshResult?.revalidate === "number" && freshResult.revalidate > 0 ? freshResult.revalidate : cached.value.cacheControl?.revalidate;
363
+ if (freshResult?.props && freshRevalidateSeconds && freshRevalidateSeconds > 0) {
235
364
  const freshHtml = await renderPagesIsrHtml({
236
365
  buildId: options.buildId,
237
366
  cachedHtml: cachedValue.html,
238
367
  createPageElement: options.createPageElement,
239
368
  i18n: options.i18n,
240
- pageProps: freshResult.props,
369
+ pageProps: freshPageProps,
370
+ props: freshRenderProps,
241
371
  params: options.params,
242
372
  renderIsrPassToStringAsync: options.renderIsrPassToStringAsync,
243
373
  routePattern: options.routePattern,
@@ -245,7 +375,7 @@ async function resolvePagesPageData(options) {
245
375
  nextData: options.nextData,
246
376
  vinext: options.vinext
247
377
  });
248
- await options.isrSet(cacheKey, buildPagesCacheValue(freshHtml, freshResult.props, options.statusCode), freshResult.revalidate, void 0, options.expireSeconds);
378
+ await options.isrSet(cacheKey, buildPagesCacheValue(freshHtml, freshRenderProps, options.statusCode), freshRevalidateSeconds, void 0, options.expireSeconds);
249
379
  }
250
380
  });
251
381
  }, {
@@ -261,24 +391,58 @@ async function resolvePagesPageData(options) {
261
391
  response: staleResponse
262
392
  };
263
393
  }
264
- const result = await options.pageModule.getStaticProps({
394
+ const generatedPageData = !options.isOnDemandRevalidate && cached?.isStale === false && cachedValue?.kind === "PAGES" && cachedValue.generatedFromDataRequest && isUnknownRecord(cachedValue.pageData) ? cachedValue.pageData : null;
395
+ if (!generatedPageData) {
396
+ const shortCircuit = await loadForegroundAppInitialRenderProps();
397
+ if (shortCircuit) return shortCircuit;
398
+ }
399
+ const result = generatedPageData ? null : await options.pageModule.getStaticProps({
265
400
  params: userFacingParams,
266
401
  locale: options.i18n.locale,
267
402
  locales: options.i18n.locales,
268
403
  defaultLocale: options.i18n.defaultLocale,
269
404
  revalidateReason: options.isOnDemandRevalidate ? "on-demand" : options.isBuildTimePrerendering ? "build" : "stale"
270
405
  });
271
- if (result?.props) pageProps = result.props;
406
+ if (generatedPageData) {
407
+ renderProps = generatedPageData;
408
+ pageProps = isUnknownRecord(renderProps.pageProps) ? renderProps.pageProps : {};
409
+ }
410
+ if (result?.props) {
411
+ pageProps = {
412
+ ...pageProps,
413
+ ...result.props
414
+ };
415
+ renderProps = {
416
+ ...renderProps,
417
+ pageProps
418
+ };
419
+ }
272
420
  if (result?.redirect) return {
273
421
  kind: "response",
274
- response: buildPagesRedirectResponse(result.redirect, options)
422
+ response: buildPagesRedirectResponse(result.redirect, options, renderProps)
275
423
  };
276
424
  if (result?.notFound) return buildPagesNotFoundResult(options);
277
425
  if (result?.props !== void 0) isSerializableProps(options.routePattern, "getStaticProps", pageProps);
278
426
  if (typeof result?.revalidate === "number" && result.revalidate > 0) isrRevalidateSeconds = result.revalidate;
427
+ else if (cachedValue?.kind === "PAGES" && cachedValue.generatedFromDataRequest) isrRevalidateSeconds = cached?.value.cacheControl?.revalidate ?? 31536e3;
428
+ if (shouldPersistFallbackData) {
429
+ const revalidateSeconds = isrRevalidateSeconds ?? 31536e3;
430
+ await options.isrSet(cacheKey, {
431
+ kind: "PAGES",
432
+ html: "",
433
+ pageData: renderProps,
434
+ generatedFromDataRequest: true,
435
+ headers: void 0,
436
+ status: void 0
437
+ }, revalidateSeconds, void 0, options.expireSeconds);
438
+ }
279
439
  }
280
- if (typeof options.pageModule.getServerSideProps !== "function" && typeof options.pageModule.getStaticProps !== "function" && hasPagesGetInitialProps(options.pageModule.default)) {
281
- const { req, res, responsePromise } = options.createGsspReqRes();
440
+ if (typeof options.pageModule.getServerSideProps !== "function" && typeof options.pageModule.getStaticProps !== "function" && hasPagesGetInitialProps(options.AppComponent)) {
441
+ const shortCircuit = await loadForegroundAppInitialRenderProps();
442
+ if (shortCircuit) return shortCircuit;
443
+ }
444
+ if (typeof options.pageModule.getServerSideProps !== "function" && typeof options.pageModule.getStaticProps !== "function" && !hasPagesGetInitialProps(options.AppComponent) && hasPagesGetInitialProps(options.pageModule.default)) {
445
+ const { req, res, responsePromise } = getSharedReqRes();
282
446
  const initialProps = await loadPagesGetInitialProps(options.pageModule.default, {
283
447
  req,
284
448
  res,
@@ -294,16 +458,23 @@ async function resolvePagesPageData(options) {
294
458
  kind: "response",
295
459
  response: await responsePromise
296
460
  };
297
- if (initialProps) pageProps = {
298
- ...pageProps,
299
- ...initialProps
300
- };
461
+ if (initialProps) {
462
+ pageProps = {
463
+ ...pageProps,
464
+ ...initialProps
465
+ };
466
+ renderProps = {
467
+ ...renderProps,
468
+ pageProps
469
+ };
470
+ }
301
471
  }
302
472
  return {
303
473
  kind: "render",
304
474
  gsspRes,
305
475
  isrRevalidateSeconds,
306
476
  pageProps,
477
+ props: renderProps,
307
478
  isFallback: false
308
479
  };
309
480
  }