vinext 0.2.0 → 1.0.0-beta.0

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 (168) hide show
  1. package/README.md +50 -29
  2. package/dist/build/client-build-config.d.ts +13 -92
  3. package/dist/build/client-build-config.js +17 -95
  4. package/dist/build/css-url-assets.d.ts +3 -1
  5. package/dist/build/css-url-assets.js +18 -1
  6. package/dist/build/inject-pregenerated-paths.d.ts +3 -0
  7. package/dist/build/inject-pregenerated-paths.js +4 -1
  8. package/dist/build/prerender-paths.d.ts +23 -0
  9. package/dist/build/prerender-paths.js +296 -0
  10. package/dist/build/prerender-server-entry.d.ts +1 -0
  11. package/dist/build/prerender-server-entry.js +49 -0
  12. package/dist/build/prerender-server-pool.d.ts +44 -0
  13. package/dist/build/prerender-server-pool.js +194 -0
  14. package/dist/build/prerender.d.ts +12 -1
  15. package/dist/build/prerender.js +87 -23
  16. package/dist/build/run-prerender.js +2 -1
  17. package/dist/cache/cache-adapters-virtual.d.ts +7 -1
  18. package/dist/cache/cache-adapters-virtual.js +26 -2
  19. package/dist/check.d.ts +4 -6
  20. package/dist/check.js +13 -9
  21. package/dist/cli.js +34 -54
  22. package/dist/client/vinext-next-data.d.ts +4 -1
  23. package/dist/config/config-matchers.js +33 -11
  24. package/dist/config/next-config.d.ts +36 -6
  25. package/dist/config/next-config.js +17 -4
  26. package/dist/config/prerender.d.ts +11 -1
  27. package/dist/config/prerender.js +19 -1
  28. package/dist/config/tsconfig-paths.js +5 -1
  29. package/dist/entries/app-browser-entry.js +5 -1
  30. package/dist/entries/app-rsc-entry.d.ts +3 -2
  31. package/dist/entries/app-rsc-entry.js +4 -0
  32. package/dist/entries/pages-client-entry.js +14 -3
  33. package/dist/entries/pages-server-entry.js +18 -4
  34. package/dist/image/image-adapters-virtual.js +1 -0
  35. package/dist/index.d.ts +1 -1
  36. package/dist/index.js +549 -152
  37. package/dist/init-cloudflare.js +12 -3
  38. package/dist/init-platform.d.ts +10 -1
  39. package/dist/init-platform.js +78 -12
  40. package/dist/init.d.ts +11 -3
  41. package/dist/init.js +129 -31
  42. package/dist/plugins/fonts.js +1 -1
  43. package/dist/plugins/ignore-dynamic-requests.js +1 -1
  44. package/dist/plugins/og-assets.js +2 -1
  45. package/dist/plugins/optimize-imports.js +1 -1
  46. package/dist/plugins/rsc-reference-validation-normalizer.d.ts +12 -0
  47. package/dist/plugins/rsc-reference-validation-normalizer.js +48 -0
  48. package/dist/plugins/sass.d.ts +17 -1
  49. package/dist/plugins/sass.js +74 -1
  50. package/dist/plugins/styled-jsx.d.ts +16 -0
  51. package/dist/plugins/styled-jsx.js +149 -0
  52. package/dist/routing/app-route-graph.js +22 -16
  53. package/dist/routing/file-matcher.d.ts +8 -1
  54. package/dist/routing/file-matcher.js +15 -3
  55. package/dist/server/app-browser-entry.js +44 -14
  56. package/dist/server/app-browser-navigation-controller.js +5 -2
  57. package/dist/server/app-browser-server-action-client.js +5 -3
  58. package/dist/server/app-browser-state.d.ts +1 -0
  59. package/dist/server/app-browser-state.js +1 -1
  60. package/dist/server/app-layout-param-observation.d.ts +1 -1
  61. package/dist/server/app-page-boundary.js +2 -1
  62. package/dist/server/app-page-cache-finalizer.d.ts +1 -0
  63. package/dist/server/app-page-cache-finalizer.js +3 -3
  64. package/dist/server/app-page-cache-render.d.ts +1 -1
  65. package/dist/server/app-page-cache.js +23 -6
  66. package/dist/server/app-page-dispatch.d.ts +2 -1
  67. package/dist/server/app-page-dispatch.js +27 -10
  68. package/dist/server/app-page-element-builder.js +1 -0
  69. package/dist/server/app-page-execution.js +2 -1
  70. package/dist/server/app-page-render-identity.d.ts +1 -0
  71. package/dist/server/app-page-render-identity.js +2 -1
  72. package/dist/server/app-page-render.d.ts +3 -1
  73. package/dist/server/app-page-render.js +67 -16
  74. package/dist/server/app-page-response.d.ts +7 -0
  75. package/dist/server/app-page-response.js +16 -4
  76. package/dist/server/app-page-route-wiring.js +3 -3
  77. package/dist/server/app-page-stream.d.ts +2 -1
  78. package/dist/server/app-page-stream.js +1 -1
  79. package/dist/server/app-route-handler-execution.d.ts +1 -1
  80. package/dist/server/app-route-tree-prefetch.d.ts +43 -0
  81. package/dist/server/app-route-tree-prefetch.js +187 -0
  82. package/dist/server/app-router-entry.js +1 -1
  83. package/dist/server/app-rsc-cache-busting.d.ts +2 -1
  84. package/dist/server/app-rsc-cache-busting.js +9 -5
  85. package/dist/server/app-rsc-handler.d.ts +6 -0
  86. package/dist/server/app-rsc-handler.js +88 -10
  87. package/dist/server/app-rsc-render-mode.d.ts +3 -5
  88. package/dist/server/app-rsc-render-mode.js +5 -12
  89. package/dist/server/app-rsc-request-normalization.d.ts +3 -4
  90. package/dist/server/app-rsc-request-normalization.js +4 -5
  91. package/dist/server/app-server-action-execution.js +6 -5
  92. package/dist/server/app-ssr-entry.js +1 -1
  93. package/dist/server/cache-control.d.ts +3 -1
  94. package/dist/server/cache-control.js +13 -1
  95. package/dist/server/dev-module-runner.js +1 -1
  96. package/dist/server/dev-origin-check.d.ts +2 -2
  97. package/dist/server/dev-origin-check.js +2 -2
  98. package/dist/server/dev-server.d.ts +11 -1
  99. package/dist/server/dev-server.js +82 -24
  100. package/dist/server/headers.d.ts +6 -2
  101. package/dist/server/headers.js +11 -5
  102. package/dist/server/image-optimization.d.ts +12 -1
  103. package/dist/server/image-optimization.js +13 -1
  104. package/dist/server/isr-cache.d.ts +13 -4
  105. package/dist/server/isr-cache.js +8 -4
  106. package/dist/server/pages-data-route.d.ts +4 -2
  107. package/dist/server/pages-data-route.js +18 -4
  108. package/dist/server/pages-dev-module-url.d.ts +2 -1
  109. package/dist/server/pages-dev-module-url.js +6 -3
  110. package/dist/server/pages-node-compat.d.ts +12 -1
  111. package/dist/server/pages-node-compat.js +50 -1
  112. package/dist/server/pages-page-data.d.ts +9 -0
  113. package/dist/server/pages-page-data.js +18 -10
  114. package/dist/server/pages-page-handler.js +19 -7
  115. package/dist/server/pages-page-response.d.ts +1 -0
  116. package/dist/server/pages-page-response.js +5 -4
  117. package/dist/server/pages-request-pipeline.d.ts +8 -6
  118. package/dist/server/pages-request-pipeline.js +31 -7
  119. package/dist/server/pages-router-entry.js +1 -1
  120. package/dist/server/prerender-manifest.d.ts +15 -1
  121. package/dist/server/prerender-manifest.js +29 -1
  122. package/dist/server/prod-server.d.ts +10 -7
  123. package/dist/server/prod-server.js +43 -28
  124. package/dist/server/request-pipeline.js +1 -1
  125. package/dist/server/static-file-cache.js +1 -1
  126. package/dist/shims/cache-handler.js +8 -1
  127. package/dist/shims/cache.d.ts +1 -1
  128. package/dist/shims/cache.js +3 -0
  129. package/dist/shims/cdn-cache.d.ts +2 -7
  130. package/dist/shims/cdn-cache.js +2 -14
  131. package/dist/shims/fetch-cache.d.ts +3 -1
  132. package/dist/shims/fetch-cache.js +77 -52
  133. package/dist/shims/internal/app-prefetch-fetch-queue.d.ts +10 -0
  134. package/dist/shims/internal/app-prefetch-fetch-queue.js +61 -0
  135. package/dist/shims/internal/hybrid-client-route-owner.d.ts +2 -1
  136. package/dist/shims/internal/hybrid-client-route-owner.js +34 -1
  137. package/dist/shims/internal/pages-data-fetch-dedup.d.ts +2 -1
  138. package/dist/shims/internal/pages-data-fetch-dedup.js +13 -2
  139. package/dist/shims/internal/pages-data-target.d.ts +8 -3
  140. package/dist/shims/internal/pages-data-target.js +9 -4
  141. package/dist/shims/link.d.ts +1 -1
  142. package/dist/shims/link.js +179 -42
  143. package/dist/shims/navigation.d.ts +15 -3
  144. package/dist/shims/navigation.js +202 -39
  145. package/dist/shims/request-context.js +18 -0
  146. package/dist/shims/request-state-types.d.ts +2 -2
  147. package/dist/shims/router.js +31 -15
  148. package/dist/shims/unified-request-context.d.ts +1 -1
  149. package/dist/shims/unified-request-context.js +1 -0
  150. package/dist/typegen.js +1 -1
  151. package/dist/utils/middleware-request-headers.js +1 -1
  152. package/dist/utils/project.d.ts +1 -1
  153. package/dist/utils/protocol-headers.d.ts +7 -1
  154. package/dist/utils/protocol-headers.js +7 -1
  155. package/dist/utils/vite-version.d.ts +4 -12
  156. package/dist/utils/vite-version.js +39 -21
  157. package/package.json +31 -13
  158. package/dist/cloudflare/index.d.ts +0 -3
  159. package/dist/cloudflare/index.js +0 -3
  160. package/dist/packages/cloudflare/src/cache/cdn-adapter.runtime.js +0 -102
  161. package/dist/packages/cloudflare/src/cache/kv-data-adapter.runtime.d.ts +0 -126
  162. package/dist/packages/cloudflare/src/cache/kv-data-adapter.runtime.js +0 -435
  163. package/dist/packages/cloudflare/src/deploy-config.js +0 -150
  164. package/dist/packages/cloudflare/src/deploy-help.js +0 -55
  165. package/dist/packages/cloudflare/src/deploy.js +0 -276
  166. package/dist/packages/cloudflare/src/tpr.d.ts +0 -45
  167. package/dist/packages/cloudflare/src/tpr.js +0 -561
  168. package/dist/packages/cloudflare/src/utils/cache-control-metadata.js +0 -20
@@ -1,5 +1,6 @@
1
1
  import { createValidFileMatcher, findFileWithExtensions } from "../routing/file-matcher.js";
2
- import { VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER } from "../utils/protocol-headers.js";
2
+ import { VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, VINEXT_PRERENDER_SECRET_HEADER, VINEXT_PRERENDER_SPECULATIVE_HEADER } from "../utils/protocol-headers.js";
3
+ import { VINEXT_PRERENDER_CACHE_LIFE_HEADER } from "../server/headers.js";
3
4
  import { classifyAppRoute, classifyPagesRoute, getAppRouteRenderEntryPath } from "./report.js";
4
5
  import { NoOpCacheHandler, getCacheHandler, setCacheHandler } from "../shims/cache-handler.js";
5
6
  import { headersContextFromRequest, runWithHeadersContext } from "../shims/headers.js";
@@ -14,6 +15,7 @@ import { readPrerenderSecret } from "./server-manifest.js";
14
15
  import { createAppPprFallbackShells, markAppPprDynamicFallbackShellHtml } from "../server/app-ppr-fallback-shell.js";
15
16
  import { getOutputPath, getRscOutputPath } from "../utils/prerender-output-paths.js";
16
17
  import { startProdServer } from "../server/prod-server.js";
18
+ import { prerenderPoolAvailable, resolvePrerenderPoolSize, startPrerenderServerPool } from "./prerender-server-pool.js";
17
19
  import fs from "node:fs";
18
20
  import path from "node:path";
19
21
  import os from "node:os";
@@ -42,6 +44,14 @@ function isExperimentalPprFallbackShellGenerationEnabled(env = process.env) {
42
44
  function getErrorMessageWithStack(err) {
43
45
  return err.stack || err.message;
44
46
  }
47
+ async function startOptionalPrerenderServerPool(outDir, poolSize) {
48
+ try {
49
+ return await startPrerenderServerPool(outDir, poolSize);
50
+ } catch (e) {
51
+ console.warn(`[vinext] prerender render pool failed to start; falling back to single-process render: ${e instanceof Error ? e.message : String(e)}`);
52
+ return null;
53
+ }
54
+ }
45
55
  var PrerenderUserFunctionError = class extends Error {};
46
56
  function parsePrerenderEndpointError(text) {
47
57
  try {
@@ -257,11 +267,12 @@ async function prerenderPages({ routes, apiRoutes, pagesDir, outDir, config, mod
257
267
  const previousPrerenderFlag = process.env.VINEXT_PRERENDER;
258
268
  process.env.VINEXT_PRERENDER = "1";
259
269
  let ownedProdServerHandle = null;
270
+ let renderPool = null;
260
271
  try {
261
272
  let prerenderSecret = options._prerenderSecret;
262
273
  if (!prerenderSecret && pagesBundlePath) prerenderSecret = readPrerenderSecret(path.dirname(pagesBundlePath));
263
274
  if (!prerenderSecret) console.warn("[vinext] Warning: prerender secret not found. /__vinext/prerender/* endpoints will return 403 and dynamic routes will produce no paths. Run `vinext build` to regenerate the secret.");
264
- const baseUrl = `http://127.0.0.1:${(options._prodServer ? options._prodServer : await (async () => {
275
+ const prodServer = options._prodServer ? options._prodServer : await (async () => {
265
276
  const srv = await startProdServer({
266
277
  port: 0,
267
278
  host: "127.0.0.1",
@@ -271,12 +282,18 @@ async function prerenderPages({ routes, apiRoutes, pagesDir, outDir, config, mod
271
282
  });
272
283
  ownedProdServerHandle = srv;
273
284
  return srv;
274
- })()).port}`;
285
+ })();
286
+ const baseUrl = `http://127.0.0.1:${prodServer.port}`;
275
287
  const secretHeaders = prerenderSecret ? { [VINEXT_PRERENDER_SECRET_HEADER]: prerenderSecret } : {};
276
- const renderPage = (urlPath) => fetch(`${baseUrl}${urlPath}`, {
277
- headers: secretHeaders,
278
- redirect: "manual"
279
- });
288
+ let renderPorts = [prodServer.port];
289
+ let renderRoundRobin = 0;
290
+ const renderPage = (urlPath) => {
291
+ const port = renderPorts[renderRoundRobin++ % renderPorts.length];
292
+ return fetch(`http://127.0.0.1:${port}${urlPath}`, {
293
+ headers: secretHeaders,
294
+ redirect: "manual"
295
+ });
296
+ };
280
297
  const bundlePageRoutes = routes.map((r) => ({
281
298
  pattern: r.pattern,
282
299
  isDynamic: r.isDynamic ?? false,
@@ -397,6 +414,13 @@ async function prerenderPages({ routes, apiRoutes, pagesDir, outDir, config, mod
397
414
  revalidate
398
415
  });
399
416
  }
417
+ if (!options._prodServer && pagesBundlePath && prerenderPoolAvailable()) {
418
+ const poolSize = resolvePrerenderPoolSize(pagesToRender.length, concurrency);
419
+ if (poolSize > 1) {
420
+ renderPool = await startOptionalPrerenderServerPool(path.dirname(path.dirname(pagesBundlePath)), poolSize);
421
+ if (renderPool) renderPorts = renderPool.ports;
422
+ }
423
+ }
400
424
  let completed = 0;
401
425
  const pageResults = await runWithConcurrency(pagesToRender, concurrency, async ({ route, urlPath, revalidate }) => {
402
426
  let result;
@@ -427,6 +451,7 @@ async function prerenderPages({ routes, apiRoutes, pagesDir, outDir, config, mod
427
451
  ...urlPath !== route.pattern ? { path: urlPath } : {}
428
452
  };
429
453
  } catch (e) {
454
+ renderPool?.recordRenderError(e);
430
455
  const err = e;
431
456
  result = {
432
457
  route: route.pattern,
@@ -443,6 +468,7 @@ async function prerenderPages({ routes, apiRoutes, pagesDir, outDir, config, mod
443
468
  return result;
444
469
  });
445
470
  results.push(...pageResults);
471
+ renderPool?.assertHealthy();
446
472
  const hasCustom404 = findFileWithExtensions(path.join(pagesDir, "404"), fileMatcher);
447
473
  const hasErrorPage = findFileWithExtensions(path.join(pagesDir, "_error"), fileMatcher);
448
474
  if (hasCustom404 || hasErrorPage) try {
@@ -460,13 +486,17 @@ async function prerenderPages({ routes, apiRoutes, pagesDir, outDir, config, mod
460
486
  router: "pages"
461
487
  });
462
488
  }
463
- } catch {}
489
+ } catch (e) {
490
+ renderPool?.recordRenderError(e);
491
+ }
492
+ renderPool?.assertHealthy();
464
493
  if (!skipManifest) writePrerenderIndex(results, manifestDir, {
465
494
  buildId: config.buildId,
466
495
  trailingSlash: config.trailingSlash
467
496
  });
468
497
  return { routes: results };
469
498
  } finally {
499
+ if (renderPool) await renderPool.close();
470
500
  setCacheHandler(previousHandler);
471
501
  if (previousPrerenderFlag === void 0) delete process.env.VINEXT_PRERENDER;
472
502
  else process.env.VINEXT_PRERENDER = previousPrerenderFlag;
@@ -505,10 +535,13 @@ async function prerenderApp({ routes, metadataRoutes = [], outDir, config, mode,
505
535
  let rscHandler;
506
536
  let staticParamsMap = {};
507
537
  let ownedProdServerHandle = null;
538
+ let renderPool = null;
539
+ let renderPorts = [];
540
+ let renderRoundRobin = 0;
508
541
  try {
509
542
  const prerenderSecret = readPrerenderSecret(serverDir);
510
543
  if (!prerenderSecret) console.warn("[vinext] Warning: prerender secret not found. /__vinext/prerender/* endpoints will return 403 and generateStaticParams will not be called. Run `vinext build` to regenerate the secret.");
511
- const baseUrl = `http://127.0.0.1:${(options._prodServer ? options._prodServer : await (async () => {
544
+ const prodServer = options._prodServer ? options._prodServer : await (async () => {
512
545
  const srv = await startProdServer({
513
546
  port: 0,
514
547
  host: "127.0.0.1",
@@ -518,11 +551,13 @@ async function prerenderApp({ routes, metadataRoutes = [], outDir, config, mode,
518
551
  });
519
552
  ownedProdServerHandle = srv;
520
553
  return srv;
521
- })()).port}`;
554
+ })();
555
+ const baseUrl = `http://127.0.0.1:${prodServer.port}`;
556
+ renderPorts = [prodServer.port];
522
557
  const secretHeaders = prerenderSecret ? { [VINEXT_PRERENDER_SECRET_HEADER]: prerenderSecret } : {};
523
558
  rscHandler = (req) => {
524
559
  const parsed = new URL(req.url);
525
- const url = `${baseUrl}${parsed.pathname}${parsed.search}`;
560
+ const url = `http://127.0.0.1:${renderPorts[renderRoundRobin++ % renderPorts.length]}${parsed.pathname}${parsed.search}`;
526
561
  return fetch(url, {
527
562
  method: req.method,
528
563
  headers: {
@@ -718,12 +753,14 @@ async function prerenderApp({ routes, metadataRoutes = [], outDir, config, mode,
718
753
  const prerenderRouteParamsHeader = serializePrerenderRouteParamsHeader(prerenderRouteParams);
719
754
  const htmlHeaders = new Headers();
720
755
  if (prerenderRouteParamsHeader !== null) htmlHeaders.set(VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, prerenderRouteParamsHeader);
756
+ if (isSpeculative) htmlHeaders.set(VINEXT_PRERENDER_SPECULATIVE_HEADER, "1");
721
757
  const htmlRequest = new Request(`http://localhost${urlPath}`, { headers: htmlHeaders });
722
758
  const htmlRender = await runWithHeadersContext(headersContextFromRequest(htmlRequest), async () => {
723
759
  const response = await rscHandler(htmlRequest);
724
760
  const cacheControl = response.headers.get("cache-control") ?? "";
725
761
  const linkHeader = response.headers.get("link");
726
- if (!response.ok || isSpeculative && cacheControl.includes("no-store")) {
762
+ const responseCacheLife = readPrerenderCacheLifeHeader(response.headers);
763
+ if (!response.ok || cacheControl.includes("no-store")) {
727
764
  await response.body?.cancel();
728
765
  return {
729
766
  cacheControl,
@@ -734,12 +771,14 @@ async function prerenderApp({ routes, metadataRoutes = [], outDir, config, mode,
734
771
  status: response.status
735
772
  };
736
773
  }
774
+ const html = await response.text();
775
+ const processCacheLife = _consumeRequestScopedCacheLife();
737
776
  return {
738
777
  cacheControl,
739
778
  linkHeader,
740
- html: await response.text(),
779
+ html,
741
780
  ok: true,
742
- requestCacheLife: _consumeRequestScopedCacheLife(),
781
+ requestCacheLife: responseCacheLife ?? processCacheLife,
743
782
  status: response.status
744
783
  };
745
784
  });
@@ -756,13 +795,11 @@ async function prerenderApp({ routes, metadataRoutes = [], outDir, config, mode,
756
795
  error: `RSC handler returned ${htmlRender.status}`
757
796
  };
758
797
  }
759
- if (isSpeculative) {
760
- if (htmlCacheControl.includes("no-store")) return {
761
- route: routePattern,
762
- status: "skipped",
763
- reason: "dynamic"
764
- };
765
- }
798
+ if (htmlCacheControl.includes("no-store")) return {
799
+ route: routePattern,
800
+ status: "skipped",
801
+ reason: "dynamic"
802
+ };
766
803
  if (htmlRender.html === null) return {
767
804
  route: routePattern,
768
805
  status: "error",
@@ -776,6 +813,7 @@ async function prerenderApp({ routes, metadataRoutes = [], outDir, config, mode,
776
813
  RSC: "1"
777
814
  });
778
815
  if (prerenderRouteParamsHeader !== null) rscHeaders.set(VINEXT_PRERENDER_ROUTE_PARAMS_HEADER, prerenderRouteParamsHeader);
816
+ if (isSpeculative) rscHeaders.set(VINEXT_PRERENDER_SPECULATIVE_HEADER, "1");
779
817
  const rscRequest = new Request(`http://localhost${urlPath}`, { headers: rscHeaders });
780
818
  const rscRes = await runWithHeadersContext(headersContextFromRequest(rscRequest), () => rscHandler(rscRequest));
781
819
  if (!rscRes.ok) {
@@ -809,6 +847,7 @@ async function prerenderApp({ routes, metadataRoutes = [], outDir, config, mode,
809
847
  ...isFallback ? { fallback: true } : {}
810
848
  };
811
849
  } catch (e) {
850
+ renderPool?.recordRenderError(e);
812
851
  if (isSpeculative) return {
813
852
  route: routePattern,
814
853
  status: "skipped",
@@ -823,6 +862,13 @@ async function prerenderApp({ routes, metadataRoutes = [], outDir, config, mode,
823
862
  };
824
863
  }
825
864
  }
865
+ if (!options._prodServer && prerenderPoolAvailable()) {
866
+ const poolSize = resolvePrerenderPoolSize(urlsToRender.length, concurrency);
867
+ if (poolSize > 1) {
868
+ renderPool = await startOptionalPrerenderServerPool(path.dirname(serverDir), poolSize);
869
+ if (renderPool) renderPorts = renderPool.ports;
870
+ }
871
+ }
826
872
  let completedApp = 0;
827
873
  const appResults = await runWithConcurrency(urlsToRender, concurrency, async (urlToRender) => {
828
874
  const result = await renderUrl(urlToRender);
@@ -835,6 +881,7 @@ async function prerenderApp({ routes, metadataRoutes = [], outDir, config, mode,
835
881
  return result;
836
882
  });
837
883
  results.push(...appResults);
884
+ renderPool?.assertHealthy();
838
885
  const outputFiles = mode === "export" && metadataRoutes.length > 0 ? emitStaticMetadataFiles(metadataRoutes, outDir) : [];
839
886
  try {
840
887
  const notFoundRequest = new Request(`http://localhost${NOT_FOUND_SENTINEL_PATH}`);
@@ -852,7 +899,10 @@ async function prerenderApp({ routes, metadataRoutes = [], outDir, config, mode,
852
899
  router: "app"
853
900
  });
854
901
  }
855
- } catch {}
902
+ } catch (e) {
903
+ renderPool?.recordRenderError(e);
904
+ }
905
+ renderPool?.assertHealthy();
856
906
  if (!skipManifest) writePrerenderIndex(results, manifestDir, {
857
907
  buildId: config.buildId,
858
908
  trailingSlash: config.trailingSlash
@@ -862,6 +912,7 @@ async function prerenderApp({ routes, metadataRoutes = [], outDir, config, mode,
862
912
  ...outputFiles.length > 0 ? { outputFiles } : {}
863
913
  };
864
914
  } finally {
915
+ if (renderPool) await renderPool.close();
865
916
  setCacheHandler(previousHandler);
866
917
  if (previousPrerenderFlag === void 0) delete process.env.VINEXT_PRERENDER;
867
918
  else process.env.VINEXT_PRERENDER = previousPrerenderFlag;
@@ -881,6 +932,19 @@ function resolveRenderedCacheControl(requestCacheLife, cacheControl, fallbackExp
881
932
  ...revalidate === void 0 ? {} : { revalidate }
882
933
  };
883
934
  }
935
+ function readPrerenderCacheLifeHeader(headers) {
936
+ const value = headers.get(VINEXT_PRERENDER_CACHE_LIFE_HEADER);
937
+ if (!value) return null;
938
+ try {
939
+ const parsed = JSON.parse(value);
940
+ const cacheLife = {};
941
+ if (typeof parsed.revalidate === "number" && Number.isFinite(parsed.revalidate)) cacheLife.revalidate = parsed.revalidate;
942
+ if (typeof parsed.expire === "number" && Number.isFinite(parsed.expire)) cacheLife.expire = parsed.expire;
943
+ return cacheLife.revalidate === void 0 && cacheLife.expire === void 0 ? null : cacheLife;
944
+ } catch {
945
+ return null;
946
+ }
947
+ }
884
948
  function resolveRenderedExpireSeconds(options) {
885
949
  const { fallbackExpireSeconds, sMaxage, staleWhileRevalidate } = options;
886
950
  if (sMaxage === void 0 || staleWhileRevalidate === void 0) return fallbackExpireSeconds;
@@ -936,4 +1000,4 @@ function writePrerenderIndex(routes, outDir, options) {
936
1000
  fs.writeFileSync(path.join(outDir, "vinext-prerender.json"), JSON.stringify(index, null, 2), "utf-8");
937
1001
  }
938
1002
  //#endregion
939
- export { extractRscPayloadFromPrerenderedHtml, prerenderApp, prerenderPages, readPrerenderSecret, resolveParentParams, writePrerenderIndex };
1003
+ export { buildUrlFromParams, extractRscPayloadFromPrerenderedHtml, prerenderApp, prerenderPages, readPrerenderSecret, resolveParentParams, writePrerenderIndex };
@@ -4,7 +4,7 @@ import { appRouter } from "../routing/app-router.js";
4
4
  import { scanMetadataFiles } from "../server/metadata-routes.js";
5
5
  import { loadNextConfig, resolveNextConfig } from "../config/next-config.js";
6
6
  import { readPrerenderSecret } from "./server-manifest.js";
7
- import { startProdServer } from "../server/prod-server.js";
7
+ import { rememberCurrentServerEntryImportMtime, startProdServer } from "../server/prod-server.js";
8
8
  import { prerenderApp, prerenderPages, writePrerenderIndex } from "./prerender.js";
9
9
  import { injectPregeneratedConcretePaths } from "./inject-pregenerated-paths.js";
10
10
  import fs from "node:fs";
@@ -224,6 +224,7 @@ async function runPrerender(options) {
224
224
  throw new Error(`Static export failed: ${errors} route${errors !== 1 ? "s" : ""} cannot be statically exported.\n${errorRoutes}\n\nRemove server-side data fetching (getServerSideProps, force-dynamic, revalidate) from these routes, or remove \`output: "export"\` from next.config.js.`);
225
225
  }
226
226
  injectPregeneratedConcretePaths(root);
227
+ if (fs.existsSync(rscBundlePath)) rememberCurrentServerEntryImportMtime(rscBundlePath);
227
228
  return {
228
229
  routes: allRoutes,
229
230
  ...allOutputFiles.length > 0 ? { outputFiles: allOutputFiles } : {}
@@ -41,10 +41,16 @@ type VinextCacheConfig = {
41
41
  };
42
42
  /** Public virtual module id imported by the server entries. */
43
43
  declare const VIRTUAL_CACHE_ADAPTERS = "virtual:vinext-cache-adapters";
44
+ declare const VINEXT_CACHE_CONFIG_PLUGIN_PROPERTY = "__vinextCacheConfig";
45
+ type ViteConfigLoader = {
46
+ loadConfigFromFile: typeof import("vite").loadConfigFromFile;
47
+ };
48
+ declare function findVinextCacheConfigInPlugins(plugins: import("vite").PluginOption[] | undefined): VinextCacheConfig | null;
49
+ declare function loadVinextCacheConfigFromViteConfig(vite: ViteConfigLoader, root: string): Promise<VinextCacheConfig | null>;
44
50
  /**
45
51
  * Generate the source of the `virtual:vinext-cache-adapters` module for the
46
52
  * given config. Always exports `registerConfiguredCacheAdapters(env)`.
47
53
  */
48
54
  declare function generateCacheAdaptersModule(cache?: VinextCacheConfig): string;
49
55
  //#endregion
50
- export { VIRTUAL_CACHE_ADAPTERS, VinextCacheConfig, generateCacheAdaptersModule };
56
+ export { VINEXT_CACHE_CONFIG_PLUGIN_PROPERTY, VIRTUAL_CACHE_ADAPTERS, VinextCacheConfig, findVinextCacheConfigInPlugins, generateCacheAdaptersModule, loadVinextCacheConfigFromViteConfig };
@@ -1,6 +1,30 @@
1
1
  //#region src/cache/cache-adapters-virtual.ts
2
2
  /** Public virtual module id imported by the server entries. */
3
3
  const VIRTUAL_CACHE_ADAPTERS = "virtual:vinext-cache-adapters";
4
+ const VINEXT_CACHE_CONFIG_PLUGIN_PROPERTY = "__vinextCacheConfig";
5
+ function flattenPluginOptions(value, target) {
6
+ if (Array.isArray(value)) {
7
+ for (const item of value) flattenPluginOptions(item, target);
8
+ return;
9
+ }
10
+ if (value) target.push(value);
11
+ }
12
+ function findVinextCacheConfigInPlugins(plugins) {
13
+ const flattened = [];
14
+ flattenPluginOptions(plugins, flattened);
15
+ for (const plugin of flattened) {
16
+ if (!plugin || typeof plugin !== "object") continue;
17
+ const cacheConfig = plugin[VINEXT_CACHE_CONFIG_PLUGIN_PROPERTY];
18
+ if (cacheConfig) return cacheConfig;
19
+ }
20
+ return null;
21
+ }
22
+ async function loadVinextCacheConfigFromViteConfig(vite, root) {
23
+ return findVinextCacheConfigInPlugins((await vite.loadConfigFromFile({
24
+ command: "build",
25
+ mode: "production"
26
+ }, void 0, root))?.config.plugins);
27
+ }
4
28
  /**
5
29
  * Serialize descriptor options into a JS expression for inlining. Plain JSON is
6
30
  * a valid JS literal; `undefined` when there are no options. Throws a clear
@@ -35,11 +59,11 @@ function generateCacheAdaptersModule(cache) {
35
59
  lines.push(`import __vinextCdnAdapterFactory from ${JSON.stringify(cdn.adapter)};`);
36
60
  lines.push(`import { setCdnCacheAdapter } from "vinext/shims/cdn-cache";`);
37
61
  }
38
- lines.push("", "// A factory that throws (e.g. a missing binding on an incompatible runtime)", "// is logged and skipped so the default handler stays in place.", "function __vinextFormatAdapterError(error) {", " if (error instanceof Error && error.message) return error.message;", " try {", " return String(error);", " } catch {", " return '<unknown error>';", " }", "}", "", "let __vinextCacheAdaptersRegistered = false;", "", "export function registerConfiguredCacheAdapters(env) {", " if (__vinextCacheAdaptersRegistered) return;", " __vinextCacheAdaptersRegistered = true;");
62
+ lines.push("", "// A factory that throws (e.g. a missing binding on an incompatible runtime)", "// is logged and skipped so the default handler stays in place.", "function __vinextFormatAdapterError(error) {", " if (error instanceof Error && error.message) return error.message;", " try {", " return String(error);", " } catch {", " return '<unknown error>';", " }", "}", "", "let __vinextCacheAdaptersRegistered = false;", "", "export function registerConfiguredCacheAdapters(env) {", " if (typeof process !== 'undefined' && process.env?.__VINEXT_PRERENDER_PATH_DISCOVERY === '1') return;", " if (__vinextCacheAdaptersRegistered) return;", " __vinextCacheAdaptersRegistered = true;");
39
63
  if (data?.adapter) lines.push(" try {", ` setDataCacheHandler(__vinextDataAdapterFactory({ env, options: ${inlineOptions(data.adapter, data.options)} }));`, " } catch (error) {", " console.warn(\"[vinext] failed to initialize the configured data cache adapter; using the default handler.\\n\" + __vinextFormatAdapterError(error));", " }");
40
64
  if (cdn?.adapter) lines.push(" try {", ` setCdnCacheAdapter(__vinextCdnAdapterFactory({ env, options: ${inlineOptions(cdn.adapter, cdn.options)} }));`, " } catch (error) {", " console.warn(\"[vinext] failed to initialize the configured CDN cache adapter; using the default adapter.\\n\" + __vinextFormatAdapterError(error));", " }");
41
65
  lines.push("}", "");
42
66
  return lines.join("\n");
43
67
  }
44
68
  //#endregion
45
- export { VIRTUAL_CACHE_ADAPTERS, generateCacheAdaptersModule };
69
+ export { VINEXT_CACHE_CONFIG_PLUGIN_PROPERTY, VIRTUAL_CACHE_ADAPTERS, findVinextCacheConfigInPlugins, generateCacheAdaptersModule, loadVinextCacheConfigFromViteConfig };
package/dist/check.d.ts CHANGED
@@ -60,9 +60,8 @@ declare function hasFreeCjsGlobal(content: string): boolean;
60
60
  /**
61
61
  * Scan source files for `import ... from 'next/...'` statements.
62
62
  *
63
- * `root` must be forward-slash: it is passed to `findSourceFiles` (which
64
- * requires it) and used as the base of `path.posix.relative`, which only yields
65
- * a canonical relative path when both operands are forward-slash.
63
+ * `root` must be forward-slash: it is passed to `findSourceFiles`, which
64
+ * requires it.
66
65
  */
67
66
  declare function scanImports(root: string): CheckItem[];
68
67
  /**
@@ -82,9 +81,8 @@ declare function checkLibraries(root: string): CheckItem[];
82
81
  /**
83
82
  * Check file conventions (pages, app directory, middleware, etc.)
84
83
  *
85
- * `root` must be forward-slash — joined with `path.posix.join`, passed to
86
- * `findDir`, and used as the base of `path.posix.relative`. Only called from
87
- * `runCheck`, which normalizes it.
84
+ * `root` must be forward-slash — joined with `path.posix.join` and passed to
85
+ * `findDir`. Only called from `runCheck`, which normalizes it.
88
86
  */
89
87
  declare function checkConventions(root: string): CheckItem[];
90
88
  /**
package/dist/check.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { detectPackageManager, findDir } from "./utils/project.js";
2
+ import { normalizePathSeparators } from "./utils/path.js";
2
3
  import fs from "node:fs";
3
4
  import path from "node:path";
4
5
  import { parseAst } from "vite";
@@ -214,6 +215,10 @@ const CONFIG_SUPPORT = {
214
215
  status: "supported",
215
216
  detail: "sourcemap-resolved stack traces during prerender"
216
217
  },
218
+ cacheComponents: {
219
+ status: "partial",
220
+ detail: "experimental support; behavior is incomplete"
221
+ },
217
222
  "experimental.ppr": {
218
223
  status: "unsupported",
219
224
  detail: "partial prerendering not yet implemented"
@@ -300,7 +305,7 @@ const CONFIG_SUPPORT = {
300
305
  },
301
306
  reactStrictMode: {
302
307
  status: "partial",
303
- detail: "config option recognized but not yet enforced; root is not wrapped in <React.StrictMode>"
308
+ detail: "enforced for the Pages Router (client root wrapped in <React.StrictMode> when true); App Router is not yet wrapped (Next.js defaults App Router strict mode on)"
304
309
  },
305
310
  poweredByHeader: {
306
311
  status: "supported",
@@ -588,9 +593,8 @@ function hasFreeCjsGlobal(content) {
588
593
  /**
589
594
  * Scan source files for `import ... from 'next/...'` statements.
590
595
  *
591
- * `root` must be forward-slash: it is passed to `findSourceFiles` (which
592
- * requires it) and used as the base of `path.posix.relative`, which only yields
593
- * a canonical relative path when both operands are forward-slash.
596
+ * `root` must be forward-slash: it is passed to `findSourceFiles`, which
597
+ * requires it.
594
598
  */
595
599
  function scanImports(root) {
596
600
  const files = findSourceFiles(root);
@@ -608,7 +612,7 @@ function scanImports(root) {
608
612
  if (mod.startsWith("next/") || mod === "next" || mod === "server-only" || mod === "client-only") {
609
613
  const normalized = mod === "next" ? "next" : mod;
610
614
  if (!importUsage.has(normalized)) importUsage.set(normalized, []);
611
- const relFile = path.posix.relative(root, file);
615
+ const relFile = normalizePathSeparators(path.relative(root, file));
612
616
  const usedInFiles = importUsage.get(normalized) ?? [];
613
617
  if (!usedInFiles.includes(relFile)) usedInFiles.push(relFile);
614
618
  }
@@ -775,6 +779,7 @@ function analyzeConfig(root) {
775
779
  "output",
776
780
  "transpilePackages",
777
781
  "webpack",
782
+ "cacheComponents",
778
783
  "reactStrictMode",
779
784
  "poweredByHeader",
780
785
  "skipMiddlewareUrlNormalize",
@@ -830,9 +835,8 @@ function checkLibraries(root) {
830
835
  /**
831
836
  * Check file conventions (pages, app directory, middleware, etc.)
832
837
  *
833
- * `root` must be forward-slash — joined with `path.posix.join`, passed to
834
- * `findDir`, and used as the base of `path.posix.relative`. Only called from
835
- * `runCheck`, which normalizes it.
838
+ * `root` must be forward-slash — joined with `path.posix.join` and passed to
839
+ * `findDir`. Only called from `runCheck`, which normalizes it.
836
840
  */
837
841
  function checkConventions(root) {
838
842
  const items = [];
@@ -931,7 +935,7 @@ function checkConventions(root) {
931
935
  const cjsGlobalFiles = [];
932
936
  for (const file of allSourceFiles) {
933
937
  const content = fs.readFileSync(file, "utf-8");
934
- const rel = path.posix.relative(root, file);
938
+ const rel = normalizePathSeparators(path.relative(root, file));
935
939
  if (viewTransitionRegex.test(content)) viewTransitionFiles.push(rel);
936
940
  if (hasFreeCjsGlobal(content)) cjsGlobalFiles.push(rel);
937
941
  }
package/dist/cli.js CHANGED
@@ -1,22 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
  import { detectPackageManager, ensureViteConfigCompatibility, hasAppDir, hasViteConfig } from "./utils/project.js";
3
+ import { normalizePathSeparators } from "./utils/path.js";
3
4
  import { formatReport, runCheck } from "./check.js";
4
5
  import { parseArgs } from "./cli-args.js";
5
6
  import { createDevServerConfigPlugin, normalizeDevServerHostname } from "./cli-dev-config.js";
6
- import { normalizePathSeparators } from "./utils/path.js";
7
7
  import { PHASE_PRODUCTION_BUILD } from "./shims/constants.js";
8
8
  import { createRscCompatibilityId, loadNextConfig, resolveNextConfig } from "./config/next-config.js";
9
9
  import { generateRouteTypes } from "./typegen.js";
10
10
  import { clearPagesClientAssetsBuildMetadata } from "./build/pages-client-assets-module.js";
11
- import { findVinextPrerenderConfigInPlugins, formatVinextPrerenderLabel, resolveVinextPrerenderDecision } from "./config/prerender.js";
11
+ import { findVinextPrerenderConfigInPlugins, findVinextRouteRootConfigInPlugins, formatVinextPrerenderLabel, resolveVinextPrerenderDecision } from "./config/prerender.js";
12
12
  import vinext from "./index.js";
13
13
  import { runPrerender } from "./build/run-prerender.js";
14
- import { loadDotenv } from "./config/dotenv.js";
15
- import { deploy, parseDeployArgs } from "./packages/cloudflare/src/deploy.js";
16
- import { printDeployHelp } from "./packages/cloudflare/src/deploy-help.js";
14
+ import { emitPrerenderPathManifest } from "./build/prerender-paths.js";
17
15
  import { getReactUpgradeDeps } from "./utils/react-version.js";
18
16
  import { init } from "./init.js";
19
- import { INIT_PLATFORMS, resolveInitPlatform, resolveInitPrerender } from "./init-platform.js";
17
+ import { resolveInitOptions } from "./init-platform.js";
18
+ import { loadDotenv } from "./config/dotenv.js";
20
19
  import { resolveVinextPackageRoot } from "./utils/vinext-root.js";
21
20
  import { emitStandaloneOutput } from "./build/standalone.js";
22
21
  import { cleanBuildOutput } from "./build/clean-output.js";
@@ -34,7 +33,6 @@ import { execFileSync } from "node:child_process";
34
33
  * vinext dev Start development server (Vite)
35
34
  * vinext build Build for production
36
35
  * vinext start Start production server
37
- * vinext deploy Deprecated Cloudflare deploy shim
38
36
  * vinext typegen Generate App Router route helper types
39
37
  * vinext lint Run linter (delegates to eslint/oxlint)
40
38
  *
@@ -128,7 +126,10 @@ function hasPagesDir() {
128
126
  return fs.existsSync(path.join(process.cwd(), "pages")) || fs.existsSync(path.join(process.cwd(), "src", "pages"));
129
127
  }
130
128
  async function loadBuildViteConfigMetadata(vite, root) {
131
- if (!hasViteConfig(root)) return { prerenderConfig: null };
129
+ if (!hasViteConfig(root)) return {
130
+ prerenderConfig: null,
131
+ routeRootConfig: null
132
+ };
132
133
  const loaded = await vite.loadConfigFromFile({
133
134
  command: "build",
134
135
  mode: "production"
@@ -136,7 +137,8 @@ async function loadBuildViteConfigMetadata(vite, root) {
136
137
  const emptyOutDir = loaded?.config.build?.emptyOutDir;
137
138
  return {
138
139
  emptyOutDir: typeof emptyOutDir === "boolean" ? emptyOutDir : void 0,
139
- prerenderConfig: findVinextPrerenderConfigInPlugins(loaded?.config.plugins)
140
+ prerenderConfig: findVinextPrerenderConfigInPlugins(loaded?.config.plugins),
141
+ routeRootConfig: findVinextRouteRootConfigInPlugins(loaded?.config.plugins)
140
142
  };
141
143
  }
142
144
  /**
@@ -277,8 +279,7 @@ async function buildApp() {
277
279
  });
278
280
  applyViteConfigCompatibility(process.cwd());
279
281
  const vite = await loadVite();
280
- const viteMajorVersion = Number.parseInt(vite.version, 10) || 7;
281
- const withBuildBundlerOptions = (bundlerOptions) => viteMajorVersion >= 8 ? { rolldownOptions: bundlerOptions } : { rollupOptions: bundlerOptions };
282
+ const withBuildBundlerOptions = (bundlerOptions) => ({ rolldownOptions: bundlerOptions });
282
283
  console.log(`\n vinext build (Vite ${getViteVersion()})\n`);
283
284
  const root = process.cwd();
284
285
  const isApp = hasAppDir(normalizePathSeparators(root));
@@ -330,7 +331,7 @@ async function buildApp() {
330
331
  mode: "production",
331
332
  isSsrBuild: true
332
333
  }, void 0, root);
333
- if (loaded?.config.plugins) userTransformPlugins = loaded.config.plugins.flat(Infinity).filter((p) => !!p && typeof p.name === "string" && !p.name.startsWith("vinext:") && !p.name.startsWith("vite:react") && !p.name.startsWith("rsc:") && p.name !== "vite-rsc-load-module-dev-proxy" && p.name !== "vite-tsconfig-paths" && !p.name.startsWith("vite-plugin-cloudflare"));
334
+ if (loaded?.config.plugins) userTransformPlugins = loaded.config.plugins.flat(Infinity).filter((p) => !!p && typeof p.name === "string" && !p.name.startsWith("vinext:") && !p.name.startsWith("vite:react") && !p.name.startsWith("rsc:") && p.name !== "vite-rsc-load-module-dev-proxy" && !p.name.startsWith("vite-plugin-cloudflare"));
334
335
  }
335
336
  await vite.build({
336
337
  root,
@@ -383,6 +384,11 @@ async function buildApp() {
383
384
  root: normalizePathSeparators(process.cwd()),
384
385
  concurrency: parsed.prerenderConcurrency
385
386
  });
387
+ await emitPrerenderPathManifest({
388
+ root: normalizePathSeparators(process.cwd()),
389
+ nextConfigOverride: resolvedNextConfig,
390
+ routeRootConfig: buildConfigMetadata.routeRootConfig
391
+ });
386
392
  }
387
393
  process.stdout.write("\x1B[0m");
388
394
  const { printBuildReport } = await import("./build/report.js");
@@ -452,33 +458,9 @@ async function lint() {
452
458
  process.exit(1);
453
459
  }
454
460
  }
455
- async function deployCommand() {
456
- const parsed = parseDeployArgs(rawArgs);
457
- if (parsed.help) {
458
- printDeployDeprecationWarning();
459
- printDeployHelp();
460
- return;
461
- }
462
- printDeployDeprecationWarning();
463
- await loadVite();
464
- console.log(`\n vinext deploy (Vite ${getViteVersion()})\n`);
465
- await deploy({
466
- root: process.cwd(),
467
- preview: parsed.preview,
468
- env: parsed.env,
469
- skipBuild: parsed.skipBuild,
470
- dryRun: parsed.dryRun,
471
- name: parsed.name,
472
- prerenderAll: parsed.prerenderAll,
473
- prerenderConcurrency: parsed.prerenderConcurrency,
474
- experimentalTPR: parsed.experimentalTPR,
475
- tprCoverage: parsed.tprCoverage,
476
- tprLimit: parsed.tprLimit,
477
- tprWindow: parsed.tprWindow
478
- });
479
- }
480
- function printDeployDeprecationWarning() {
481
- console.log(" ⚠️ Warning: `vinext deploy` has moved to the `@vinext/cloudflare` package.\n Please switch to `npx @vinext/cloudflare deploy` or `vp exec vinext-cloudflare deploy`; this compatibility command will be removed in a future release.\n");
461
+ function failRemovedDeployCommand() {
462
+ console.error("\n Error: `vinext deploy` has moved to the `@vinext/cloudflare` package.\n\n Run `npx @vinext/cloudflare deploy` or `vp exec vinext-cloudflare deploy` instead.\n");
463
+ process.exit(1);
482
464
  }
483
465
  async function check() {
484
466
  if (parseArgs(rawArgs).help) return printHelp("check");
@@ -508,17 +490,13 @@ async function initCommand() {
508
490
  const port = parsed.port ?? 3001;
509
491
  const skipCheck = rawArgs.includes("--skip-check");
510
492
  const force = rawArgs.includes("--force");
511
- const platform = await resolveInitPlatform(rawArgs);
512
- const platformOptions = await INIT_PLATFORMS[platform].options(rawArgs);
513
- const prerender = await resolveInitPrerender(rawArgs);
493
+ const initOptions = await resolveInitOptions(rawArgs);
514
494
  await init({
515
495
  root: process.cwd(),
516
496
  port,
517
497
  skipCheck,
518
498
  force,
519
- platform,
520
- prerender,
521
- cloudflare: platform === "cloudflare" ? platformOptions : void 0
499
+ ...initOptions
522
500
  });
523
501
  }
524
502
  function printHelp(cmd) {
@@ -574,11 +552,7 @@ function printHelp(cmd) {
574
552
  `);
575
553
  return;
576
554
  }
577
- if (cmd === "deploy") {
578
- printDeployDeprecationWarning();
579
- printDeployHelp();
580
- return;
581
- }
555
+ if (cmd === "deploy") failRemovedDeployCommand();
582
556
  if (cmd === "check") {
583
557
  console.log(`
584
558
  vinext check - Scan Next.js app for compatibility
@@ -611,6 +585,11 @@ function printHelp(cmd) {
611
585
  --platform <target> Deployment target: cloudflare or node
612
586
  --prerender Configure vinext build to pre-render all static routes
613
587
  (default: prompt, with No selected by default)
588
+ --experimental-warm-cdn-cache
589
+ Add experimental CDN pre-warming to the Cloudflare deploy script
590
+ (Workers Cache CDN only, default: prompt with No)
591
+ --cdn-cache <type> Cloudflare CDN cache: workers-cache or data-cache
592
+ (default: workers-cache)
614
593
  --data-cache <type> Cloudflare data cache: kv or none (default: kv)
615
594
  --image-optimization <type>
616
595
  Cloudflare image optimization: cloudflare-images or none
@@ -619,11 +598,15 @@ function printHelp(cmd) {
619
598
  Examples:
620
599
  vinext init Prompt for a deployment platform
621
600
  vinext init --platform=cloudflare Configure Cloudflare Workers (default)
601
+ vinext init --platform=cloudflare --cdn-cache=data-cache
602
+ Fall through CDN caching to the data cache
622
603
  vinext init --platform=cloudflare --data-cache=kv
623
604
  Configure the default Cloudflare cache handlers
624
605
  vinext init --platform=cloudflare --image-optimization=none
625
606
  Do not configure Cloudflare Images
626
607
  vinext init --prerender Add prerender: { routes: "*" } to vite.config.ts
608
+ vinext init --experimental-warm-cdn-cache
609
+ Add experimental CDN pre-warming to deploy:vinext
627
610
  vinext init --platform=node Configure a Node deployment
628
611
  vinext init -p 4000 Use port 4000 for dev:vinext
629
612
  vinext init --force Overwrite existing vite.config.ts
@@ -722,10 +705,7 @@ switch (command) {
722
705
  });
723
706
  break;
724
707
  case "deploy":
725
- deployCommand().catch((e) => {
726
- console.error(e);
727
- process.exit(1);
728
- });
708
+ failRemovedDeployCommand();
729
709
  break;
730
710
  case "init":
731
711
  initCommand().catch((e) => {