vinext 0.1.3 → 0.1.5

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 (185) hide show
  1. package/dist/build/client-build-config.d.ts +11 -2
  2. package/dist/build/client-build-config.js +17 -6
  3. package/dist/build/css-url-assets.d.ts +1 -1
  4. package/dist/build/css-url-assets.js +9 -7
  5. package/dist/build/prerender.js +3 -1
  6. package/dist/cache/cache-adapters-virtual.js +1 -1
  7. package/dist/client/pages-router-link-navigation.d.ts +33 -7
  8. package/dist/client/pages-router-link-navigation.js +32 -2
  9. package/dist/client/vinext-next-data.js +2 -0
  10. package/dist/cloudflare/src/cache/kv-data-adapter.runtime.d.ts +1 -1
  11. package/dist/config/config-matchers.d.ts +11 -1
  12. package/dist/config/config-matchers.js +14 -2
  13. package/dist/config/tsconfig-paths.js +14 -1
  14. package/dist/deploy.js +20 -13
  15. package/dist/entries/app-rsc-entry.js +27 -22
  16. package/dist/entries/pages-client-entry.js +14 -13
  17. package/dist/entries/pages-server-entry.js +8 -27
  18. package/dist/index.js +365 -147
  19. package/dist/plugins/css-data-url.js +30 -26
  20. package/dist/plugins/dynamic-preload-metadata.js +2 -4
  21. package/dist/plugins/extensionless-dynamic-import.js +27 -24
  22. package/dist/plugins/fonts.js +5 -4
  23. package/dist/plugins/import-meta-url.js +21 -15
  24. package/dist/plugins/instrumentation-client.js +1 -1
  25. package/dist/plugins/middleware-server-only.js +7 -6
  26. package/dist/plugins/og-assets.js +48 -46
  27. package/dist/plugins/optimize-imports.js +9 -3
  28. package/dist/plugins/remove-console.d.ts +7 -1
  29. package/dist/plugins/remove-console.js +4 -1
  30. package/dist/plugins/require-context.js +21 -20
  31. package/dist/plugins/strip-server-exports.d.ts +16 -8
  32. package/dist/plugins/strip-server-exports.js +496 -46
  33. package/dist/routing/app-route-graph.js +2 -2
  34. package/dist/server/app-bfcache-identity.d.ts +26 -0
  35. package/dist/server/app-bfcache-identity.js +127 -0
  36. package/dist/server/app-browser-action-result.js +1 -1
  37. package/dist/server/app-browser-entry.js +22 -12
  38. package/dist/server/app-browser-navigation-controller.d.ts +1 -1
  39. package/dist/server/app-browser-navigation-controller.js +1 -1
  40. package/dist/server/app-browser-state.d.ts +3 -22
  41. package/dist/server/app-browser-state.js +23 -139
  42. package/dist/server/app-browser-stream.js +1 -1
  43. package/dist/server/app-browser-visible-commit.d.ts +1 -1
  44. package/dist/server/app-browser-visible-commit.js +3 -2
  45. package/dist/server/app-fallback-renderer.d.ts +1 -1
  46. package/dist/server/app-layout-param-observation.d.ts +1 -1
  47. package/dist/server/app-layout-param-observation.js +1 -1
  48. package/dist/server/app-middleware.js +2 -1
  49. package/dist/server/app-page-boundary-render.d.ts +1 -1
  50. package/dist/server/app-page-boundary.js +1 -1
  51. package/dist/server/app-page-cache-finalizer.d.ts +62 -0
  52. package/dist/server/app-page-cache-finalizer.js +122 -0
  53. package/dist/server/app-page-cache-render.d.ts +2 -2
  54. package/dist/server/app-page-cache-render.js +1 -1
  55. package/dist/server/app-page-cache.d.ts +2 -53
  56. package/dist/server/app-page-cache.js +5 -131
  57. package/dist/server/app-page-dispatch.d.ts +2 -2
  58. package/dist/server/app-page-dispatch.js +10 -8
  59. package/dist/server/app-page-probe.js +3 -2
  60. package/dist/server/app-page-render-observation.js +2 -2
  61. package/dist/server/app-page-render.d.ts +3 -3
  62. package/dist/server/app-page-render.js +3 -2
  63. package/dist/server/app-page-stream.d.ts +2 -9
  64. package/dist/server/app-page-stream.js +1 -35
  65. package/dist/server/app-pages-bridge.d.ts +5 -1
  66. package/dist/server/app-pages-bridge.js +5 -13
  67. package/dist/server/app-request-context.d.ts +1 -2
  68. package/dist/server/app-request-context.js +2 -1
  69. package/dist/server/app-route-handler-dispatch.js +3 -2
  70. package/dist/server/app-route-handler-execution.d.ts +1 -1
  71. package/dist/server/app-route-handler-execution.js +1 -1
  72. package/dist/server/app-route-handler-response.d.ts +1 -1
  73. package/dist/server/app-router-entry.js +2 -1
  74. package/dist/server/app-rsc-handler.d.ts +3 -0
  75. package/dist/server/app-rsc-handler.js +73 -31
  76. package/dist/server/app-rsc-response-finalizer.js +1 -1
  77. package/dist/server/app-rsc-route-matching.js +6 -2
  78. package/dist/server/app-server-action-execution.d.ts +1 -1
  79. package/dist/server/app-server-action-execution.js +10 -6
  80. package/dist/server/app-ssr-entry.d.ts +1 -1
  81. package/dist/server/app-ssr-entry.js +12 -38
  82. package/dist/server/app-ssr-router-instance.d.ts +6 -0
  83. package/dist/server/app-ssr-router-instance.js +24 -0
  84. package/dist/server/app-ssr-stream.js +1 -1
  85. package/dist/server/artifact-compatibility.js +1 -1
  86. package/dist/server/before-interactive-head.d.ts +17 -0
  87. package/dist/server/before-interactive-head.js +35 -0
  88. package/dist/server/client-reuse-manifest.js +1 -1
  89. package/dist/server/csp.js +1 -4
  90. package/dist/server/defer-until-stream-consumed.d.ts +7 -0
  91. package/dist/server/defer-until-stream-consumed.js +34 -0
  92. package/dist/server/dev-server.js +82 -37
  93. package/dist/server/instrumentation.js +1 -1
  94. package/dist/server/isr-cache.d.ts +1 -1
  95. package/dist/server/isr-cache.js +1 -1
  96. package/dist/server/isr-decision.d.ts +1 -1
  97. package/dist/server/middleware-matcher.js +20 -9
  98. package/dist/server/middleware-runtime.d.ts +3 -4
  99. package/dist/server/middleware-runtime.js +4 -2
  100. package/dist/server/navigation-planner.d.ts +3 -12
  101. package/dist/server/navigation-planner.js +24 -0
  102. package/dist/server/navigation-trace.d.ts +2 -1
  103. package/dist/server/navigation-trace.js +1 -0
  104. package/dist/server/open-redirect.d.ts +12 -0
  105. package/dist/server/open-redirect.js +21 -0
  106. package/dist/server/operation-token.d.ts +40 -0
  107. package/dist/server/operation-token.js +85 -0
  108. package/dist/server/pages-data-route.d.ts +1 -1
  109. package/dist/server/pages-data-route.js +7 -4
  110. package/dist/server/pages-dev-module-url.d.ts +4 -0
  111. package/dist/server/pages-dev-module-url.js +15 -0
  112. package/dist/server/pages-document-initial-props.d.ts +4 -15
  113. package/dist/server/pages-document-initial-props.js +27 -56
  114. package/dist/server/pages-i18n.js +2 -2
  115. package/dist/server/pages-page-data.d.ts +1 -1
  116. package/dist/server/pages-page-data.js +3 -1
  117. package/dist/server/pages-page-handler.js +3 -1
  118. package/dist/server/pages-page-response.d.ts +3 -1
  119. package/dist/server/pages-page-response.js +6 -6
  120. package/dist/server/pages-readiness.js +1 -1
  121. package/dist/server/pages-request-pipeline.d.ts +7 -7
  122. package/dist/server/pages-request-pipeline.js +63 -21
  123. package/dist/server/prod-server.d.ts +3 -1
  124. package/dist/server/prod-server.js +43 -11
  125. package/dist/server/request-pipeline.d.ts +1 -24
  126. package/dist/server/request-pipeline.js +1 -33
  127. package/dist/server/seed-cache.d.ts +1 -1
  128. package/dist/server/static-file-cache.js +16 -4
  129. package/dist/shims/before-interactive-context.d.ts +14 -3
  130. package/dist/shims/cache-handler.d.ts +106 -0
  131. package/dist/shims/cache-handler.js +176 -0
  132. package/dist/shims/cache-request-state.d.ts +47 -0
  133. package/dist/shims/cache-request-state.js +126 -0
  134. package/dist/shims/cache-runtime.d.ts +2 -2
  135. package/dist/shims/cache-runtime.js +3 -14
  136. package/dist/shims/cache.d.ts +3 -231
  137. package/dist/shims/cache.js +17 -383
  138. package/dist/shims/cdn-cache.d.ts +1 -1
  139. package/dist/shims/cdn-cache.js +1 -1
  140. package/dist/shims/document.d.ts +15 -20
  141. package/dist/shims/document.js +5 -8
  142. package/dist/shims/error-boundary-navigation.d.ts +7 -0
  143. package/dist/shims/error-boundary-navigation.js +44 -0
  144. package/dist/shims/error-boundary.js +10 -8
  145. package/dist/shims/error.js +2 -1
  146. package/dist/shims/fetch-cache.js +1 -1
  147. package/dist/shims/form.js +1 -1
  148. package/dist/shims/image.js +74 -9
  149. package/dist/shims/internal/app-page-props-cache-key.d.ts +5 -0
  150. package/dist/shims/internal/app-page-props-cache-key.js +16 -0
  151. package/dist/shims/internal/navigation-untracked.js +2 -1
  152. package/dist/shims/internal/pages-data-fetch-dedup.d.ts +6 -7
  153. package/dist/shims/internal/pages-data-fetch-dedup.js +67 -14
  154. package/dist/shims/internal/pages-data-target.js +1 -1
  155. package/dist/shims/layout-segment-context.d.ts +1 -1
  156. package/dist/shims/layout-segment-context.js +2 -1
  157. package/dist/shims/link.js +38 -17
  158. package/dist/shims/metadata.js +4 -4
  159. package/dist/shims/navigation-context-state.d.ts +40 -0
  160. package/dist/shims/navigation-context-state.js +116 -0
  161. package/dist/shims/navigation-errors.d.ts +55 -0
  162. package/dist/shims/navigation-errors.js +110 -0
  163. package/dist/shims/navigation-server.d.ts +3 -0
  164. package/dist/shims/navigation-server.js +3 -0
  165. package/dist/shims/navigation-state.d.ts +1 -2
  166. package/dist/shims/navigation-state.js +2 -1
  167. package/dist/shims/navigation.d.ts +3 -291
  168. package/dist/shims/navigation.js +16 -445
  169. package/dist/shims/navigation.react-server.d.ts +2 -2
  170. package/dist/shims/navigation.react-server.js +3 -1
  171. package/dist/shims/request-state-types.d.ts +3 -3
  172. package/dist/shims/router.d.ts +6 -2
  173. package/dist/shims/router.js +99 -20
  174. package/dist/shims/script.js +9 -5
  175. package/dist/shims/slot.js +3 -1
  176. package/dist/shims/unified-request-context.d.ts +2 -2
  177. package/dist/utils/has-trailing-comma.d.ts +24 -0
  178. package/dist/utils/has-trailing-comma.js +62 -0
  179. package/dist/utils/text-stream.d.ts +1 -1
  180. package/dist/utils/text-stream.js +2 -2
  181. package/dist/utils/virtual-module.d.ts +5 -0
  182. package/dist/utils/virtual-module.js +0 -0
  183. package/dist/utils/vite-version.d.ts +12 -1
  184. package/dist/utils/vite-version.js +9 -1
  185. package/package.json +5 -1
@@ -7,6 +7,13 @@ type ClientAssetFileNameInfo = {
7
7
  readonly originalFileName?: string;
8
8
  readonly originalFileNames?: readonly string[];
9
9
  };
10
+ type RscFrameworkModuleInfo = {
11
+ importers: string[];
12
+ isEntry: boolean;
13
+ };
14
+ type RscFrameworkManualChunksMeta = {
15
+ getModuleInfo(id: string): RscFrameworkModuleInfo | null;
16
+ };
10
17
  /**
11
18
  * Routes client assets into Next-compatible subtrees: `.css` sources go to
12
19
  * `<assetsDir>/css/`, everything else to `<assetsDir>/media/`. Returned as a
@@ -80,18 +87,20 @@ declare function isRscFrameworkModule(id: string): boolean;
80
87
  * dedicated "framework" chunk in the RSC server build. Returns the bundler-
81
88
  * appropriate shape: rolldown's `codeSplitting` for Vite 8+, Rollup's
82
89
  * `manualChunks` for Vite 7. See {@link RSC_FRAMEWORK_CHUNK_TEST} for the
83
- * motivation (issue #1549).
90
+ * motivation (issue #1549). Framework modules that are only reachable through
91
+ * dynamic imports must stay out of the eager framework chunk (issue #2073).
84
92
  */
85
93
  declare function createRscFrameworkChunkOutputConfig(viteMajorVersion: number): {
86
94
  codeSplitting: {
87
95
  groups: {
88
96
  name: string;
89
97
  test: RegExp;
98
+ entriesAware: boolean;
90
99
  }[];
91
100
  };
92
101
  manualChunks?: undefined;
93
102
  } | {
94
- manualChunks(id: string): string | undefined;
103
+ manualChunks(id: string, meta: RscFrameworkManualChunksMeta): string | undefined;
95
104
  codeSplitting?: undefined;
96
105
  };
97
106
  /**
@@ -33,9 +33,10 @@ function createClientAssetFileNames(assetsDir) {
33
33
  * (node_modules/.pnpm/pkg@ver/node_modules/pkg).
34
34
  */
35
35
  function getPackageName(id) {
36
- const nmIdx = id.lastIndexOf("node_modules/");
36
+ const normalizedId = id.replaceAll("\\", "/");
37
+ const nmIdx = normalizedId.lastIndexOf("node_modules/");
37
38
  if (nmIdx === -1) return null;
38
- const rest = id.slice(nmIdx + 13);
39
+ const rest = normalizedId.slice(nmIdx + 13);
39
40
  if (rest.startsWith("@")) {
40
41
  const parts = rest.split("/");
41
42
  return parts.length >= 2 ? parts[0] + "/" + parts[1] : null;
@@ -153,20 +154,30 @@ function isRscFrameworkModule(id) {
153
154
  const pkg = getPackageName(id);
154
155
  return pkg !== null && FRAMEWORK_PACKAGES.includes(pkg);
155
156
  }
157
+ function isStaticallyReachableFromEntry(id, meta, visited = /* @__PURE__ */ new Set()) {
158
+ if (visited.has(id)) return false;
159
+ visited.add(id);
160
+ const moduleInfo = meta.getModuleInfo(id);
161
+ if (!moduleInfo) return false;
162
+ if (moduleInfo.isEntry) return true;
163
+ return moduleInfo.importers.some((importer) => isStaticallyReachableFromEntry(importer, meta, visited));
164
+ }
156
165
  /**
157
166
  * Output config that isolates React (and the RSC flight runtime) into a
158
167
  * dedicated "framework" chunk in the RSC server build. Returns the bundler-
159
168
  * appropriate shape: rolldown's `codeSplitting` for Vite 8+, Rollup's
160
169
  * `manualChunks` for Vite 7. See {@link RSC_FRAMEWORK_CHUNK_TEST} for the
161
- * motivation (issue #1549).
170
+ * motivation (issue #1549). Framework modules that are only reachable through
171
+ * dynamic imports must stay out of the eager framework chunk (issue #2073).
162
172
  */
163
173
  function createRscFrameworkChunkOutputConfig(viteMajorVersion) {
164
174
  if (viteMajorVersion >= 8) return { codeSplitting: { groups: [{
165
175
  name: "framework",
166
- test: RSC_FRAMEWORK_CHUNK_TEST
176
+ test: RSC_FRAMEWORK_CHUNK_TEST,
177
+ entriesAware: true
167
178
  }] } };
168
- return { manualChunks(id) {
169
- return isRscFrameworkModule(id) ? "framework" : void 0;
179
+ return { manualChunks(id, meta) {
180
+ return isRscFrameworkModule(id) && isStaticallyReachableFromEntry(id, meta) ? "framework" : void 0;
170
181
  } };
171
182
  }
172
183
  /**
@@ -10,7 +10,7 @@ type EmitRestoredCssUrlAsset = (asset: {
10
10
  /**
11
11
  * Append the private provenance marker to each relative asset `url()` in a CSS
12
12
  * source. Idempotent and side-effect free (only adds a query param), so it is
13
- * safe to run on every client-environment stylesheet, vendored CSS included.
13
+ * safe to run on every build-environment stylesheet, vendored CSS included.
14
14
  */
15
15
  declare function markCssUrlAssetReferences(code: string, id: string): string | null;
16
16
  /**
@@ -12,12 +12,14 @@
12
12
  * vitejs/vite#8632). The one native escape hatch is `this.emitFile({ fileName })`:
13
13
  * assets emitted with an explicit `fileName` are *never* deduped. So we:
14
14
  *
15
- * 1. mark — during the client CSS transform, tag each relative asset `url()`
16
- * with a private `?vinext_css_url_asset=<source-basename>` query. This is
17
- * the only durable carrier of per-reference provenance: once Rolldown
18
- * dedupes, the emitted bundle cannot tell which `url()` came from which
19
- * source, and the bundle metadata (`originalFileNames`) records the set of
20
- * sources but not the mapping per reference.
15
+ * 1. mark — during every production CSS transform, tag each relative asset
16
+ * `url()` with a private `?vinext_css_url_asset=<source-basename>` query.
17
+ * Using identical transformed CSS in server and client environments is
18
+ * required because the default CSS Modules scoped name hashes the full CSS
19
+ * text. The marker is also the only durable carrier of per-reference
20
+ * provenance: once Rolldown dedupes, the emitted bundle cannot tell which
21
+ * `url()` came from which source, and bundle metadata records the source
22
+ * set but not the mapping per reference.
21
23
  *
22
24
  * 2. restore — at `generateBundle`, read each marked reference's source
23
25
  * basename back out. When it differs from the deduped output's basename,
@@ -109,7 +111,7 @@ function rewriteCssUrls(code, replace) {
109
111
  /**
110
112
  * Append the private provenance marker to each relative asset `url()` in a CSS
111
113
  * source. Idempotent and side-effect free (only adds a query param), so it is
112
- * safe to run on every client-environment stylesheet, vendored CSS included.
114
+ * safe to run on every build-environment stylesheet, vendored CSS included.
113
115
  */
114
116
  function markCssUrlAssetReferences(code, id) {
115
117
  if (!isCssRequest(id) || !code.includes("url(")) return null;
@@ -1,8 +1,9 @@
1
1
  import { createValidFileMatcher, findFileWithExtensions } from "../routing/file-matcher.js";
2
2
  import { VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER } from "../server/headers.js";
3
3
  import { normalizeStaticPathsEntry } from "../routing/route-pattern.js";
4
+ import { NoOpCacheHandler, getCacheHandler, setCacheHandler } from "../shims/cache-handler.js";
4
5
  import { headersContextFromRequest, runWithHeadersContext } from "../shims/headers.js";
5
- import { NoOpCacheHandler, _consumeRequestScopedCacheLife, getCacheHandler, setCacheHandler } from "../shims/cache.js";
6
+ import { _consumeRequestScopedCacheLife } from "../shims/cache-request-state.js";
6
7
  import { classifyAppRoute, classifyPagesRoute, getAppRouteRenderEntryPath } from "./report.js";
7
8
  import { BLOCKED_PAGES } from "../shims/constants.js";
8
9
  import { concatUint8Arrays, decodeRscEmbeddedChunk } from "../server/app-rsc-embedded-chunks.js";
@@ -659,6 +660,7 @@ async function prerenderApp({ routes, metadataRoutes = [], outDir, config, mode,
659
660
  for (const params of paramSets) {
660
661
  if (params === null || params === void 0) throw new Error(`generateStaticParams() for ${route.pattern} returned an entry with no params object.`);
661
662
  const urlPath = buildUrlFromParams(route.pattern, params);
663
+ if (queuedRouteUrls.has(urlPath)) continue;
662
664
  queuedRouteUrls.add(urlPath);
663
665
  urlsToRender.push({
664
666
  urlPath,
@@ -29,7 +29,7 @@ function generateCacheAdaptersModule(cache) {
29
29
  const lines = ["// vinext: generated from the `cache` option in your vinext() plugin config."];
30
30
  if (data?.adapter) {
31
31
  lines.push(`import __vinextDataAdapterFactory from ${JSON.stringify(data.adapter)};`);
32
- lines.push(`import { setDataCacheHandler } from "vinext/shims/cache";`);
32
+ lines.push(`import { setDataCacheHandler } from "vinext/shims/cache-handler";`);
33
33
  }
34
34
  if (cdn?.adapter) {
35
35
  lines.push(`import __vinextCdnAdapterFactory from ${JSON.stringify(cdn.adapter)};`);
@@ -3,23 +3,49 @@ type PagesRouterLinkTransitionOptions = {
3
3
  scroll?: boolean;
4
4
  shallow?: boolean;
5
5
  locale?: string | false;
6
+ _vinextInterpolateDynamicRoute?: boolean;
6
7
  };
7
8
  type PagesRouterLinkRuntime = {
8
9
  push(url: string, as?: string, options?: PagesRouterLinkTransitionOptions): Promise<boolean>;
9
10
  replace(url: string, as?: string, options?: PagesRouterLinkTransitionOptions): Promise<boolean>;
10
11
  };
12
+ type PagesRouterLinkNavigation = {
13
+ href: string;
14
+ replace: boolean;
15
+ scroll: boolean;
16
+ shallow?: boolean;
17
+ locale?: string | false;
18
+ interpolateDynamicRoute?: boolean;
19
+ };
20
+ declare function resolvePagesRouterQueryOnlyHref(href: string, {
21
+ asPath,
22
+ basePath,
23
+ fallbackHref,
24
+ locales
25
+ }: {
26
+ asPath?: string;
27
+ basePath: string;
28
+ fallbackHref: string;
29
+ locales?: readonly string[];
30
+ }): string;
11
31
  declare function navigatePagesRouterLink(router: PagesRouterLinkRuntime, {
12
32
  href,
13
33
  replace,
14
34
  scroll,
15
35
  shallow,
16
- locale
36
+ locale,
37
+ interpolateDynamicRoute
38
+ }: PagesRouterLinkNavigation): Promise<void>;
39
+ declare function navigatePagesRouterLinkWithFallback({
40
+ router,
41
+ loadRouter,
42
+ navigation,
43
+ fallback
17
44
  }: {
18
- href: string;
19
- replace: boolean;
20
- scroll: boolean;
21
- shallow?: boolean;
22
- locale?: string | false;
45
+ router?: PagesRouterLinkRuntime;
46
+ loadRouter: () => Promise<PagesRouterLinkRuntime | undefined>;
47
+ navigation: PagesRouterLinkNavigation;
48
+ fallback: () => void;
23
49
  }): Promise<void>;
24
50
  //#endregion
25
- export { navigatePagesRouterLink };
51
+ export { navigatePagesRouterLink, navigatePagesRouterLinkWithFallback, resolvePagesRouterQueryOnlyHref };
@@ -1,12 +1,42 @@
1
+ import { stripBasePath } from "../utils/base-path.js";
2
+ import { getLocalePathPrefix } from "../utils/domain-locale.js";
1
3
  //#region src/client/pages-router-link-navigation.ts
2
- async function navigatePagesRouterLink(router, { href, replace, scroll, shallow, locale }) {
4
+ function resolvePagesRouterQueryOnlyHref(href, { asPath, basePath, fallbackHref, locales }) {
5
+ if (!href.startsWith("?")) return href;
6
+ try {
7
+ const fallbackUrl = new URL(fallbackHref);
8
+ const base = new URL(asPath ?? `${stripBasePath(fallbackUrl.pathname, basePath)}${fallbackUrl.search}${fallbackUrl.hash}`, "http://vinext.local");
9
+ const locale = getLocalePathPrefix(base.pathname, locales);
10
+ if (locale) base.pathname = base.pathname.slice(locale.length + 1) || "/";
11
+ const resolved = new URL(href, base);
12
+ return resolved.href.slice(resolved.origin.length);
13
+ } catch {
14
+ return href;
15
+ }
16
+ }
17
+ async function navigatePagesRouterLink(router, { href, replace, scroll, shallow, locale, interpolateDynamicRoute = false }) {
3
18
  const routerOptions = {
4
19
  scroll,
5
20
  locale
6
21
  };
22
+ if (interpolateDynamicRoute) routerOptions._vinextInterpolateDynamicRoute = true;
7
23
  if (shallow !== void 0) routerOptions.shallow = shallow;
8
24
  if (replace) await router.replace(href, void 0, routerOptions);
9
25
  else await router.push(href, void 0, routerOptions);
10
26
  }
27
+ async function navigatePagesRouterLinkWithFallback({ router, loadRouter, navigation, fallback }) {
28
+ let pagesRouter = router;
29
+ if (!pagesRouter) try {
30
+ pagesRouter = await loadRouter();
31
+ } catch {
32
+ fallback();
33
+ return;
34
+ }
35
+ if (!pagesRouter) {
36
+ fallback();
37
+ return;
38
+ }
39
+ await navigatePagesRouterLink(pagesRouter, navigation);
40
+ }
11
41
  //#endregion
12
- export { navigatePagesRouterLink };
42
+ export { navigatePagesRouterLink, navigatePagesRouterLinkWithFallback, resolvePagesRouterQueryOnlyHref };
@@ -1,6 +1,8 @@
1
1
  import { isUnknownRecord } from "../utils/record.js";
2
2
  //#region src/client/vinext-next-data.ts
3
3
  function extractVinextNextDataJson(html) {
4
+ const canonical = /<script\b(?=[^>]*\bid=["']__NEXT_DATA__["'])(?=[^>]*\btype=["']application\/json["'])[^>]*>([\s\S]*?)<\/script>/.exec(html);
5
+ if (canonical) return canonical[1];
4
6
  const assignment = /<script(?:\s[^>]*)?>\s*window\.__NEXT_DATA__\s*=\s*/.exec(html);
5
7
  if (!assignment || assignment.index === void 0) return null;
6
8
  let start = assignment.index + assignment[0].length;
@@ -1,5 +1,5 @@
1
+ import { CacheHandler, CacheHandlerValue, IncrementalCacheValue } from "../../../shims/cache-handler.js";
1
2
  import { ExecutionContextLike } from "../../../shims/request-context.js";
2
- import { CacheHandler, CacheHandlerValue, IncrementalCacheValue } from "../../../shims/cache.js";
3
3
 
4
4
  //#region ../cloudflare/src/cache/kv-data-adapter.runtime.d.ts
5
5
  type KVNamespace = {
@@ -148,6 +148,16 @@ declare function matchRedirect(pathname: string, redirects: NextRedirect[], ctx:
148
148
  * when evaluating rewrites, so this parameter is required.
149
149
  */
150
150
  declare function matchRewrite(pathname: string, rewrites: NextRewrite[], ctx: RequestContext, basePathState?: BasePathMatchState): string | null;
151
+ /**
152
+ * Check whether a rewrite source can match a pathname without evaluating its
153
+ * request-dependent `has` / `missing` conditions.
154
+ *
155
+ * Dev uses this only as a conservative preflight before middleware runs. The
156
+ * conditions may become true after middleware overrides request headers, so
157
+ * evaluating them against the original request would incorrectly skip the
158
+ * Pages request pipeline for file-looking paths.
159
+ */
160
+ declare function matchesRewriteSource(pathname: string, rewrite: NextRewrite, basePathState?: BasePathMatchState): boolean;
151
161
  /**
152
162
  * Sanitize a redirect/rewrite destination to collapse protocol-relative URLs.
153
163
  *
@@ -244,4 +254,4 @@ declare function applyLocaleToRoutes<T extends NextRedirect | NextRewrite>(route
244
254
  trailingSlash?: boolean;
245
255
  }): T[];
246
256
  //#endregion
247
- export { BasePathMatchState, RequestContext, applyLocaleToRoutes, applyMiddlewareRequestHeaders, checkHasConditions, escapeHeaderSource, isExternalUrl, isSafeRegex, matchConfigPattern, matchHeaders, matchRedirect, matchRewrite, normalizeHost, parseCookies, preserveRedirectDestinationQuery, proxyExternalRequest, requestContextFromRequest, safeRegExp, sanitizeDestination };
257
+ export { BasePathMatchState, RequestContext, applyLocaleToRoutes, applyMiddlewareRequestHeaders, checkHasConditions, escapeHeaderSource, isExternalUrl, isSafeRegex, matchConfigPattern, matchHeaders, matchRedirect, matchRewrite, matchesRewriteSource, normalizeHost, parseCookies, preserveRedirectDestinationQuery, proxyExternalRequest, requestContextFromRequest, safeRegExp, sanitizeDestination };
@@ -268,7 +268,7 @@ function isSafeRegex(pattern) {
268
268
  */
269
269
  function safeRegExp(pattern, flags) {
270
270
  if (!isSafeRegex(pattern)) {
271
- console.warn(`[vinext] Ignoring potentially unsafe regex pattern (ReDoS risk): ${pattern}\n Patterns with nested quantifiers (e.g. (a+)+) can cause catastrophic backtracking.\n Simplify the pattern to avoid nested repetition.`);
271
+ console.warn(`[vinext] Rejecting potentially unsafe regex pattern (ReDoS risk): ${pattern}\n Patterns with nested quantifiers (e.g. (a+)+) can cause catastrophic backtracking.\n Simplify the pattern to avoid nested repetition.`);
272
272
  return null;
273
273
  }
274
274
  try {
@@ -718,6 +718,18 @@ function matchRewrite(pathname, rewrites, ctx, basePathState = _BASEPATH_DEFAULT
718
718
  return null;
719
719
  }
720
720
  /**
721
+ * Check whether a rewrite source can match a pathname without evaluating its
722
+ * request-dependent `has` / `missing` conditions.
723
+ *
724
+ * Dev uses this only as a conservative preflight before middleware runs. The
725
+ * conditions may become true after middleware overrides request headers, so
726
+ * evaluating them against the original request would incorrectly skip the
727
+ * Pages request pipeline for file-looking paths.
728
+ */
729
+ function matchesRewriteSource(pathname, rewrite, basePathState = _BASEPATH_DEFAULT) {
730
+ return shouldEvaluateRule(rewrite.basePath, basePathState) && matchConfigPattern(pathname, rewrite.source) !== null;
731
+ }
732
+ /**
721
733
  * Substitute all matched route params into a redirect/rewrite destination.
722
734
  *
723
735
  * Handles repeated params (e.g. `/api/:id/:id`) and catch-all suffix forms
@@ -1031,4 +1043,4 @@ function applyLocaleToRoutes(routes, i18n, type, options = {}) {
1031
1043
  return out;
1032
1044
  }
1033
1045
  //#endregion
1034
- export { applyLocaleToRoutes, applyMiddlewareRequestHeaders, checkHasConditions, escapeHeaderSource, isExternalUrl, isSafeRegex, matchConfigPattern, matchHeaders, matchRedirect, matchRewrite, normalizeHost, parseCookies, preserveRedirectDestinationQuery, proxyExternalRequest, requestContextFromRequest, safeRegExp, sanitizeDestination };
1046
+ export { applyLocaleToRoutes, applyMiddlewareRequestHeaders, checkHasConditions, escapeHeaderSource, isExternalUrl, isSafeRegex, matchConfigPattern, matchHeaders, matchRedirect, matchRewrite, matchesRewriteSource, normalizeHost, parseCookies, preserveRedirectDestinationQuery, proxyExternalRequest, requestContextFromRequest, safeRegExp, sanitizeDestination };
@@ -38,6 +38,19 @@ function resolveTsconfigPathCandidate(candidate) {
38
38
  for (const item of candidates) if (fs.existsSync(item) && fs.statSync(item).isFile()) return item;
39
39
  return null;
40
40
  }
41
+ /**
42
+ * Normalize a tsconfig `extends` field into a list of specifier strings.
43
+ *
44
+ * TypeScript 5.0+ allows `extends` to be either a string or an array of
45
+ * strings. Matches Next.js's handling in
46
+ * packages/next/src/build/next-config-ts/transpile-config.ts, where parents
47
+ * are iterated in order and later entries override earlier ones.
48
+ */
49
+ function normalizeExtends(extendsField) {
50
+ if (typeof extendsField === "string") return [extendsField];
51
+ if (Array.isArray(extendsField)) return extendsField.filter((value) => typeof value === "string");
52
+ return [];
53
+ }
41
54
  function resolveTsconfigExtends(configPath, specifier) {
42
55
  const fromDir = path.dirname(configPath);
43
56
  if (specifier.startsWith(".") || specifier.startsWith("/") || specifier.startsWith("\\")) return resolveTsconfigPathCandidate(path.resolve(fromDir, specifier));
@@ -87,7 +100,7 @@ function loadResolutionFromTsconfigFile(configPath, seen) {
87
100
  }
88
101
  if (!parsed) return emptyResolution();
89
102
  let resolution = emptyResolution();
90
- const extendsList = typeof parsed.extends === "string" ? [parsed.extends] : [];
103
+ const extendsList = normalizeExtends(parsed.extends);
91
104
  for (const extendsSpecifier of extendsList) {
92
105
  const extendedPath = resolveTsconfigExtends(configPath, extendsSpecifier);
93
106
  if (extendedPath) {
package/dist/deploy.js CHANGED
@@ -374,7 +374,7 @@ function generatePagesRouterWorkerEntry() {
374
374
  * Cloudflare Worker entry point -- auto-generated by vinext deploy.
375
375
  * Edit freely or delete to regenerate on next deploy.
376
376
  */
377
- import { runPagesRequest, wrapMiddlewareWithBasePath } from "vinext/server/pages-request-pipeline";
377
+ import { fetchWorkerFilesystemRoute, runPagesRequest, wrapMiddlewareWithBasePath } from "vinext/server/pages-request-pipeline";
378
378
  import type { PagesPipelineDeps } from "vinext/server/pages-request-pipeline";
379
379
  import { handleImageOptimization, DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, isImageOptimizationPath } from "vinext/server/image-optimization";
380
380
  import type { ImageConfig } from "vinext/server/image-optimization";
@@ -384,7 +384,7 @@ import { assetPrefixPathname, isNextStaticPath } from "vinext/utils/asset-prefix
384
384
  import { hasBasePath, stripBasePath } from "vinext/utils/base-path";
385
385
 
386
386
  // @ts-expect-error -- virtual module resolved by vinext at build time
387
- import { renderPage, handleApiRoute, runMiddleware, vinextConfig, matchPageRoute } from "virtual:vinext-server-entry";
387
+ import { renderPage, handleApiRoute, runMiddleware, normalizeDataRequest, vinextConfig, matchPageRoute } from "virtual:vinext-server-entry";
388
388
  // @ts-expect-error -- virtual module resolved by vinext at build time
389
389
  import { registerConfiguredCacheAdapters } from "virtual:vinext-cache-adapters";
390
390
 
@@ -448,11 +448,6 @@ export default {
448
448
  return notFoundStaticAssetResponse();
449
449
  }
450
450
 
451
- // Capture x-nextjs-data before filterInternalHeaders strips it -- the
452
- // middleware redirect protocol needs to know whether the inbound request
453
- // was a _next/data fetch to emit x-nextjs-redirect instead of a 3xx.
454
- const isDataRequest = request.headers.get("x-nextjs-data") === "1";
455
-
456
451
  // Strip internal headers from inbound requests so they cannot be
457
452
  // forged to influence routing or impersonate internal state.
458
453
  // Request.headers is immutable in Workers, so build a clean copy.
@@ -476,6 +471,14 @@ export default {
476
471
  }
477
472
  }
478
473
 
474
+ const dataNorm = normalizeDataRequest(request);
475
+ if (dataNorm.notFoundResponse) return dataNorm.notFoundResponse;
476
+ const isDataReq = dataNorm.isDataReq;
477
+ if (isDataReq) {
478
+ request = dataNorm.request;
479
+ pathname = dataNorm.normalizedPathname;
480
+ }
481
+
479
482
  // ── Image optimization via Cloudflare Images binding ──────────
480
483
  // Checked after basePath stripping so /<basePath>/_next/image works.
481
484
  if (isImageOptimizationPath(pathname)) {
@@ -504,12 +507,8 @@ export default {
504
507
  configRewrites,
505
508
  configHeaders,
506
509
  hadBasePath,
507
- // The worker adapter does not do _next/data URL normalization (no
508
- // buildId available at request time). isDataReq is used by the pipeline
509
- // only for renderPage options and shouldDeferErrorPageOnMiss -- false
510
- // is correct here.
511
- isDataReq: false,
512
- isDataRequest,
510
+ isDataReq,
511
+ isDataRequest: isDataReq,
513
512
  ctx,
514
513
  matchPageRoute: typeof matchPageRoute === "function" ? matchPageRoute : null,
515
514
  // Pass the original (pre-basePath-stripping) URL to middleware so that
@@ -527,6 +526,14 @@ export default {
527
526
  handleApi: typeof handleApiRoute === "function"
528
527
  ? (req, apiUrl) => handleApiRoute(req, apiUrl, ctx)
529
528
  : null,
529
+ serveFilesystemRoute: async (requestPathname, _stagedHeaders, phase) => {
530
+ return fetchWorkerFilesystemRoute(
531
+ request,
532
+ requestPathname,
533
+ phase,
534
+ (assetRequest) => env.ASSETS.fetch(assetRequest),
535
+ );
536
+ },
530
537
  };
531
538
 
532
539
  const result = await runPagesRequest(request, deps);
@@ -18,7 +18,6 @@ const DEFAULT_EXPIRE_TIME = 31536e3;
18
18
  const DEFAULT_REACT_MAX_HEADERS_LENGTH = 6e3;
19
19
  const middlewareRequestHeadersPath = resolveEntryPath("../server/middleware-request-headers.js", import.meta.url);
20
20
  const normalizePathModulePath = resolveEntryPath("../server/normalize-path.js", import.meta.url);
21
- const appRscHandlerPath = resolveEntryPath("../server/app-rsc-handler.js", import.meta.url);
22
21
  const appRouteHandlerDispatchPath = resolveEntryPath("../server/app-route-handler-dispatch.js", import.meta.url);
23
22
  const appRouteHandlerResponsePath = resolveEntryPath("../server/app-route-handler-response.js", import.meta.url);
24
23
  const appServerActionExecutionPath = resolveEntryPath("../server/app-server-action-execution.js", import.meta.url);
@@ -110,29 +109,21 @@ const prerenderToReadableStream = createRscPrerenderer(async (model, options) =>
110
109
  );
111
110
  import { createElement } from "react";
112
111
  import { getNavigationContext as _getNavigationContext } from "next/navigation";
113
- import { configureMemoryCacheHandler as __configureMemoryCacheHandler } from "next/cache";
112
+ import { configureMemoryCacheHandler as __configureMemoryCacheHandler } from "vinext/shims/cache-handler";
114
113
  import { headersContextFromRequest, getDraftModeCookieHeader, getAndClearPendingCookies, consumeDynamicUsage, consumeInvalidDynamicUsageError, setHeadersAccessPhase } from "next/headers";
115
114
  import { mergeMetadata, resolveModuleMetadata, mergeViewport, resolveModuleViewport } from "vinext/metadata";
116
115
  ${middlewarePath ? `import * as middlewareModule from ${JSON.stringify(normalizePathSeparators(middlewarePath))};` : ""}
117
116
  ${instrumentationPath ? `import * as _instrumentation from ${JSON.stringify(normalizePathSeparators(instrumentationPath))};
118
117
  import { ensureInstrumentationRegistered as __ensureInstrumentationRegistered } from ${JSON.stringify(instrumentationRuntimePath)};` : ""}
119
- import { createAppRscHandler as __createAppRscHandler } from ${JSON.stringify(appRscHandlerPath)};
118
+ import { createAppRscHandler } from "vinext/server/app-rsc-handler";
120
119
  import { registerConfiguredCacheAdapters as __registerConfiguredCacheAdapters } from "virtual:vinext-cache-adapters";
121
120
  import { decodePathParams as __decodePathParams } from ${JSON.stringify(normalizePathModulePath)};
122
121
  import { buildRequestHeadersFromMiddlewareResponse as __buildRequestHeadersFromMiddlewareResponse } from ${JSON.stringify(middlewareRequestHeadersPath)};
123
- import {
124
- dispatchAppRouteHandler as __dispatchAppRouteHandler,
125
- } from ${JSON.stringify(appRouteHandlerDispatchPath)};
126
- import {
122
+ ${hasPagesDir ? `import {
127
123
  applyRouteHandlerMiddlewareContext as __applyRouteHandlerMiddlewareContext,
128
- } from ${JSON.stringify(appRouteHandlerResponsePath)};
129
- import {
130
- handleProgressiveServerActionRequest as __handleProgressiveServerActionRequest,
131
- handleServerActionRscRequest as __handleServerActionRscRequest,
132
- isProgressiveServerActionRequest as __isProgressiveServerActionRequest,
133
- readActionBodyWithLimit as __readBodyWithLimit,
134
- readActionFormDataWithLimit as __readFormDataWithLimit,
135
- } from ${JSON.stringify(appServerActionExecutionPath)};
124
+ } from ${JSON.stringify(appRouteHandlerResponsePath)};` : ""}
125
+ const __loadAppRouteHandlerDispatch = () => import(${JSON.stringify(appRouteHandlerDispatchPath)});
126
+ const __loadAppServerActionExecution = () => import(${JSON.stringify(appServerActionExecutionPath)});
136
127
  import {
137
128
  sanitizeErrorForClient as __sanitizeErrorForClient,
138
129
  } from ${JSON.stringify(appRscErrorsPath)};
@@ -198,7 +189,6 @@ import { clearAppRequestContext as __clearRequestContext, setAppNavigationContex
198
189
  __configureMemoryCacheHandler({ cacheMaxMemorySize: ${JSON.stringify(cacheMaxMemorySize)} });
199
190
  import { createAppPrerenderStaticParamsResolver as __createAppPrerenderStaticParamsResolver } from ${JSON.stringify(appPrerenderStaticParamsPath)};
200
191
  import { ensureAppRouteModulesLoaded as __ensureRouteLoaded } from ${JSON.stringify(appRouteModuleLoaderPath)};
201
- import { seedMemoryCacheFromPrerender as __seedMemoryCacheFromPrerender } from ${JSON.stringify(seedCachePath)};
202
192
  import {
203
193
  getRenderedConcreteUrlPathsForRoute as __getRenderedConcreteUrlPathsForRoute,
204
194
  initPregeneratedPathsFromGlobals as __initPregeneratedPathsFromGlobals,
@@ -408,7 +398,9 @@ export const __hasPagesDir = ${JSON.stringify(hasPagesDir)};
408
398
  export const getRenderedConcreteUrlPathsForRoute = __getRenderedConcreteUrlPathsForRoute;
409
399
  const __cacheComponents = ${JSON.stringify(cacheComponents)};
410
400
 
411
- export function seedMemoryCacheFromPrerender(serverDir) {
401
+ export async function seedMemoryCacheFromPrerender(serverDir) {
402
+ const { seedMemoryCacheFromPrerender: __seedMemoryCacheFromPrerender } =
403
+ await import(${JSON.stringify(seedCachePath)});
412
404
  return __seedMemoryCacheFromPrerender(serverDir, {
413
405
  buildAppPageHtmlKey(pathname) {
414
406
  return __isrHtmlKey(pathname);
@@ -450,8 +442,9 @@ const rootParamNamesMap = {
450
442
  ${rootParamNameEntries.join("\n")}
451
443
  };
452
444
 
453
- export default __createAppRscHandler({
445
+ export default createAppRscHandler({
454
446
  basePath: __basePath,
447
+ buildId: process.env.__VINEXT_BUILD_ID ?? null,
455
448
  ensureRouteLoaded: __ensureRouteLoaded,
456
449
  clearRequestContext() {
457
450
  __clearRequestContext();
@@ -651,7 +644,7 @@ export default __createAppRscHandler({
651
644
  renderMode,
652
645
  });
653
646
  },
654
- dispatchMatchedRouteHandler({
647
+ async dispatchMatchedRouteHandler({
655
648
  cleanPathname,
656
649
  middlewareContext,
657
650
  params,
@@ -659,6 +652,8 @@ export default __createAppRscHandler({
659
652
  route,
660
653
  searchParams,
661
654
  }) {
655
+ const { dispatchAppRouteHandler: __dispatchAppRouteHandler } =
656
+ await __loadAppRouteHandlerDispatch();
662
657
  return __dispatchAppRouteHandler({
663
658
  basePath: __basePath,
664
659
  cleanPathname,
@@ -688,13 +683,18 @@ export default __createAppRscHandler({
688
683
  ${instrumentationPath ? `ensureInstrumentation() {
689
684
  return __ensureInstrumentationRegistered(_instrumentation);
690
685
  },` : ""}
691
- handleProgressiveActionRequest({
686
+ async handleProgressiveActionRequest({
692
687
  actionId,
693
688
  cleanPathname,
694
689
  contentType,
695
690
  middlewareContext,
696
691
  request,
697
692
  }) {
693
+ const {
694
+ handleProgressiveServerActionRequest: __handleProgressiveServerActionRequest,
695
+ isProgressiveServerActionRequest: __isProgressiveServerActionRequest,
696
+ readActionFormDataWithLimit: __readFormDataWithLimit,
697
+ } = await __loadAppServerActionExecution();
698
698
  // A multipart form POST to a page is always a server-action attempt, so a
699
699
  // body that decodes to no action must surface as 404 action-not-found
700
700
  // (#1340). Route handlers run after this dispatch and accept raw multipart
@@ -748,6 +748,11 @@ export default __createAppRscHandler({
748
748
  request,
749
749
  searchParams,
750
750
  }) {
751
+ const {
752
+ handleServerActionRscRequest: __handleServerActionRscRequest,
753
+ readActionBodyWithLimit: __readBodyWithLimit,
754
+ readActionFormDataWithLimit: __readFormDataWithLimit,
755
+ } = await __loadAppServerActionExecution();
751
756
  const __actionMatch = matchRoute(cleanPathname);
752
757
  if (__actionMatch) await __ensureRouteLoaded(__actionMatch.route);
753
758
  const __actionIsEdgeRuntime = __actionMatch
@@ -867,9 +872,9 @@ export default __createAppRscHandler({
867
872
  const __isEdge = route ? __isEdgeRuntime(__resolveAppPageSegmentConfig({ layouts: route.layouts, page: route.page }).runtime) : false;
868
873
  return __fallbackRenderer.renderNotFound(route, isRscRequest, request, matchedParams, scriptNonce, middlewareContext, { isEdgeRuntime: __isEdge });
869
874
  },
870
- ${hasPagesDir ? `async renderPagesFallback({ allowRscDocumentFallback, appRouteMatch, isRscRequest, matchKind, middlewareContext, pathname, request, url }) {
875
+ ${hasPagesDir ? `async renderPagesFallback({ allowRscDocumentFallback, appRouteMatch, isDataRequest, isRscRequest, matchKind, middlewareContext, pathname, pagesDataRequest, request, url }) {
871
876
  return __renderPagesFallback(
872
- { allowRscDocumentFallback, appRouteMatch, isRscRequest, matchKind, middlewareContext, pathname, request, url },
877
+ { allowRscDocumentFallback, appRouteMatch, isDataRequest, isRscRequest, matchKind, middlewareContext, pathname, pagesDataRequest, request, url },
873
878
  {
874
879
  loadPagesEntry() {
875
880
  return import.meta.viteRsc.loadModule("ssr", "index");
@@ -50,19 +50,10 @@ async function generateClientEntry(pagesDir, nextConfig, fileMatcher, options =
50
50
  import "vinext/instrumentation-client";
51
51
  import React from "react";
52
52
  import { hydrateRoot } from "react-dom/client";
53
- // Statically import next/router as the very first vinext shim so that
54
- // (a) installWindowNext runs at top-level — \`window.next.router\` is
55
- // available to test harnesses and third-party scripts BEFORE
56
- // hydrate() resolves (see .nextjs-ref/packages/next/src/client/next.ts
57
- // line 13, which also sets window.next as a top-level side effect),
58
- // and (b) the popstate handler is registered before
59
- // installPagesRouterRuntime() runs, removing the race window where a
60
- // popstate event could fire between hydration and runtime install.
61
- //
62
- // Mirrors Next.js's bootstrap order: client/next.ts statically imports
63
- // from './' before calling initialize/hydrate, so window.next is set up
64
- // before any async work.
65
- import Router, { wrapWithRouterContext } from "next/router";
53
+ import Router, {
54
+ wrapWithRouterContext,
55
+ _initializePagesRouterReadyFromNextData,
56
+ } from "next/router";
66
57
 
67
58
  const pageLoaders = {
68
59
  ${loaderEntries.join(",\n")}
@@ -110,6 +101,14 @@ window.__VINEXT_LINK_PREFETCH_ROUTES__ = ${JSON.stringify(appPrefetchRoutes)};
110
101
  window.__VINEXT_PAGES_LINK_PREFETCH_ROUTES__ = ${JSON.stringify(pagesPrefetchRoutes)};
111
102
  window.__VINEXT_CLIENT_REWRITES__ = ${JSON.stringify(nextConfig.rewrites)};
112
103
 
104
+ const nextDataElement = document.getElementById("__NEXT_DATA__");
105
+ if (nextDataElement?.textContent) {
106
+ window.__NEXT_DATA__ = JSON.parse(nextDataElement.textContent);
107
+ window.__VINEXT_LOCALE__ = window.__NEXT_DATA__.locale;
108
+ window.__VINEXT_LOCALES__ = window.__NEXT_DATA__.locales;
109
+ window.__VINEXT_DEFAULT_LOCALE__ = window.__NEXT_DATA__.defaultLocale;
110
+ }
111
+
113
112
  async function hydrate() {
114
113
  const nextData = window.__NEXT_DATA__;
115
114
  if (!nextData) {
@@ -117,6 +116,8 @@ async function hydrate() {
117
116
  return;
118
117
  }
119
118
 
119
+ _initializePagesRouterReadyFromNextData(nextData);
120
+
120
121
  let hydrateRootOptions;
121
122
  if (import.meta.env.DEV) {
122
123
  const overlay = await import("vinext/dev-error-overlay");