@vercel/next 4.0.11 → 4.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -9677,7 +9677,7 @@ async function getRoutesManifest(entryPath, outputDirectory, nextVersion) {
9677
9677
  }
9678
9678
  return routesManifest;
9679
9679
  }
9680
- async function getDynamicRoutes(entryPath, entryDirectory, dynamicPages, isDev, routesManifest, omittedRoutes, canUsePreviewMode, bypassToken, isServerMode, dynamicMiddlewareRouteMap) {
9680
+ async function getDynamicRoutes(entryPath, entryDirectory, dynamicPages, isDev, routesManifest, omittedRoutes, canUsePreviewMode, bypassToken, isServerMode, dynamicMiddlewareRouteMap, experimentalPPR) {
9681
9681
  if (routesManifest) {
9682
9682
  switch (routesManifest.version) {
9683
9683
  case 1:
@@ -9730,6 +9730,20 @@ async function getDynamicRoutes(entryPath, entryDirectory, dynamicPages, isDev,
9730
9730
  }
9731
9731
  ];
9732
9732
  }
9733
+ if (experimentalPPR) {
9734
+ let dest = route.dest?.replace(/($|\?)/, ".prefetch.rsc$1");
9735
+ if (page === "/" || page === "/index") {
9736
+ dest = dest?.replace(/([^/]+\.prefetch\.rsc(\?.*|$))/, "__$1");
9737
+ }
9738
+ routes2.push({
9739
+ ...route,
9740
+ src: route.src.replace(
9741
+ new RegExp((0, import_escape_string_regexp.default)("(?:/)?$")),
9742
+ "(?:\\.prefetch\\.rsc)(?:/)?$"
9743
+ ),
9744
+ dest
9745
+ });
9746
+ }
9733
9747
  routes2.push({
9734
9748
  ...route,
9735
9749
  src: route.src.replace(
@@ -9739,7 +9753,6 @@ async function getDynamicRoutes(entryPath, entryDirectory, dynamicPages, isDev,
9739
9753
  dest: route.dest?.replace(/($|\?)/, ".rsc$1")
9740
9754
  });
9741
9755
  routes2.push(route);
9742
- continue;
9743
9756
  }
9744
9757
  return routes2;
9745
9758
  }
@@ -10152,47 +10165,68 @@ async function getPrerenderManifest(entryPath, outputDirectory) {
10152
10165
  let initialStatus;
10153
10166
  let initialHeaders;
10154
10167
  let experimentalBypassFor;
10168
+ let experimentalPPR;
10169
+ let prefetchDataRoute;
10155
10170
  if (manifest.version === 4) {
10156
10171
  initialStatus = manifest.routes[route].initialStatus;
10157
10172
  initialHeaders = manifest.routes[route].initialHeaders;
10158
10173
  experimentalBypassFor = manifest.routes[route].experimentalBypassFor;
10174
+ experimentalPPR = manifest.routes[route].experimentalPPR;
10175
+ prefetchDataRoute = manifest.routes[route].prefetchDataRoute;
10159
10176
  }
10160
10177
  ret.staticRoutes[route] = {
10161
10178
  initialRevalidate: initialRevalidateSeconds === false ? false : Math.max(1, initialRevalidateSeconds),
10162
10179
  dataRoute,
10180
+ prefetchDataRoute,
10163
10181
  srcRoute,
10164
10182
  initialStatus,
10165
10183
  initialHeaders,
10166
- experimentalBypassFor
10184
+ experimentalBypassFor,
10185
+ experimentalPPR
10167
10186
  };
10168
10187
  });
10169
10188
  lazyRoutes.forEach((lazyRoute) => {
10170
10189
  const { routeRegex, fallback, dataRoute, dataRouteRegex } = manifest.dynamicRoutes[lazyRoute];
10171
10190
  let experimentalBypassFor;
10191
+ let experimentalPPR;
10192
+ let prefetchDataRoute;
10193
+ let prefetchDataRouteRegex;
10172
10194
  if (manifest.version === 4) {
10173
10195
  experimentalBypassFor = manifest.dynamicRoutes[lazyRoute].experimentalBypassFor;
10196
+ experimentalPPR = manifest.dynamicRoutes[lazyRoute].experimentalPPR;
10197
+ prefetchDataRoute = manifest.dynamicRoutes[lazyRoute].prefetchDataRoute;
10198
+ prefetchDataRouteRegex = manifest.dynamicRoutes[lazyRoute].prefetchDataRouteRegex;
10174
10199
  }
10175
10200
  if (typeof fallback === "string") {
10176
10201
  ret.fallbackRoutes[lazyRoute] = {
10177
10202
  experimentalBypassFor,
10203
+ experimentalPPR,
10178
10204
  routeRegex,
10179
10205
  fallback,
10180
10206
  dataRoute,
10181
- dataRouteRegex
10207
+ dataRouteRegex,
10208
+ prefetchDataRoute,
10209
+ prefetchDataRouteRegex
10182
10210
  };
10183
10211
  } else if (fallback === null) {
10184
10212
  ret.blockingFallbackRoutes[lazyRoute] = {
10185
10213
  experimentalBypassFor,
10214
+ experimentalPPR,
10186
10215
  routeRegex,
10187
10216
  dataRoute,
10188
- dataRouteRegex
10217
+ dataRouteRegex,
10218
+ prefetchDataRoute,
10219
+ prefetchDataRouteRegex
10189
10220
  };
10190
10221
  } else {
10191
10222
  ret.omittedRoutes[lazyRoute] = {
10192
10223
  experimentalBypassFor,
10224
+ experimentalPPR,
10193
10225
  routeRegex,
10194
10226
  dataRoute,
10195
- dataRouteRegex
10227
+ dataRouteRegex,
10228
+ prefetchDataRoute,
10229
+ prefetchDataRouteRegex
10196
10230
  };
10197
10231
  }
10198
10232
  });
@@ -10322,6 +10356,7 @@ async function getPageLambdaGroups({
10322
10356
  functionsConfigManifest,
10323
10357
  pages,
10324
10358
  prerenderRoutes,
10359
+ experimentalPPRRoutes,
10325
10360
  pageTraces,
10326
10361
  compressedPages,
10327
10362
  tracedPseudoLayer,
@@ -10336,6 +10371,7 @@ async function getPageLambdaGroups({
10336
10371
  const newPages = [...internalPages, page];
10337
10372
  const routeName = normalizePage(page.replace(/\.js$/, ""));
10338
10373
  const isPrerenderRoute = prerenderRoutes.has(routeName);
10374
+ const isExperimentalPPR = experimentalPPRRoutes?.has(routeName) ?? false;
10339
10375
  let opts = {};
10340
10376
  if (functionsConfigManifest && functionsConfigManifest.functions[routeName]) {
10341
10377
  opts = functionsConfigManifest.functions[routeName];
@@ -10353,7 +10389,7 @@ async function getPageLambdaGroups({
10353
10389
  opts = { ...vercelConfigOpts, ...opts };
10354
10390
  }
10355
10391
  let matchingGroup = groups.find((group) => {
10356
- const matches = group.maxDuration === opts.maxDuration && group.memory === opts.memory && group.isPrerenders === isPrerenderRoute;
10392
+ const matches = group.maxDuration === opts.maxDuration && group.memory === opts.memory && group.isPrerenders === isPrerenderRoute && group.isExperimentalPPR === isExperimentalPPR;
10357
10393
  if (matches) {
10358
10394
  let newTracedFilesSize = group.pseudoLayerBytes;
10359
10395
  let newTracedFilesUncompressedSize = group.pseudoLayerUncompressedBytes;
@@ -10381,6 +10417,7 @@ async function getPageLambdaGroups({
10381
10417
  pages: [page],
10382
10418
  ...opts,
10383
10419
  isPrerenders: isPrerenderRoute,
10420
+ isExperimentalPPR,
10384
10421
  isApiLambda: !!isApiPage(page),
10385
10422
  pseudoLayerBytes: initialPseudoLayer.pseudoLayerBytes,
10386
10423
  pseudoLayerUncompressedBytes: initialPseudoLayerUncompressed,
@@ -10562,7 +10599,7 @@ var onPrerenderRouteInitial = (prerenderManifest, canUsePreviewMode, entryDirect
10562
10599
  };
10563
10600
  };
10564
10601
  var prerenderGroup = 1;
10565
- var onPrerenderRoute = (prerenderRouteArgs) => (routeKey, {
10602
+ var onPrerenderRoute = (prerenderRouteArgs) => async (routeKey, {
10566
10603
  isBlocking,
10567
10604
  isFallback,
10568
10605
  isOmitted,
@@ -10579,6 +10616,7 @@ var onPrerenderRoute = (prerenderRouteArgs) => (routeKey, {
10579
10616
  isServerMode,
10580
10617
  canUsePreviewMode,
10581
10618
  lambdas,
10619
+ experimentalStreamingLambdaPaths,
10582
10620
  prerenders,
10583
10621
  pageLambdaMap,
10584
10622
  routesManifest,
@@ -10621,9 +10659,11 @@ var onPrerenderRoute = (prerenderRouteArgs) => (routeKey, {
10621
10659
  let initialRevalidate;
10622
10660
  let srcRoute;
10623
10661
  let dataRoute;
10662
+ let prefetchDataRoute;
10624
10663
  let initialStatus;
10625
10664
  let initialHeaders;
10626
10665
  let experimentalBypassFor;
10666
+ let experimentalPPR;
10627
10667
  if (isFallback || isBlocking) {
10628
10668
  const pr = isFallback ? prerenderManifest.fallbackRoutes[routeKey] : prerenderManifest.blockingFallbackRoutes[routeKey];
10629
10669
  initialRevalidate = 1;
@@ -10636,11 +10676,15 @@ var onPrerenderRoute = (prerenderRouteArgs) => (routeKey, {
10636
10676
  srcRoute = null;
10637
10677
  dataRoute = pr.dataRoute;
10638
10678
  experimentalBypassFor = pr.experimentalBypassFor;
10679
+ experimentalPPR = pr.experimentalPPR;
10680
+ prefetchDataRoute = pr.prefetchDataRoute;
10639
10681
  } else if (isOmitted) {
10640
10682
  initialRevalidate = false;
10641
10683
  srcRoute = routeKey;
10642
10684
  dataRoute = prerenderManifest.omittedRoutes[routeKey].dataRoute;
10643
10685
  experimentalBypassFor = prerenderManifest.omittedRoutes[routeKey].experimentalBypassFor;
10686
+ experimentalPPR = prerenderManifest.omittedRoutes[routeKey].experimentalPPR;
10687
+ prefetchDataRoute = prerenderManifest.omittedRoutes[routeKey].prefetchDataRoute;
10644
10688
  } else {
10645
10689
  const pr = prerenderManifest.staticRoutes[routeKey];
10646
10690
  ({
@@ -10649,7 +10693,9 @@ var onPrerenderRoute = (prerenderRouteArgs) => (routeKey, {
10649
10693
  dataRoute,
10650
10694
  initialHeaders,
10651
10695
  initialStatus,
10652
- experimentalBypassFor
10696
+ experimentalBypassFor,
10697
+ experimentalPPR,
10698
+ prefetchDataRoute
10653
10699
  } = pr);
10654
10700
  }
10655
10701
  let isAppPathRoute = false;
@@ -10658,7 +10704,38 @@ var onPrerenderRoute = (prerenderRouteArgs) => (routeKey, {
10658
10704
  }
10659
10705
  const isOmittedOrNotFound = isOmitted || isNotFound;
10660
10706
  let htmlFsRef;
10661
- if (appDir && !dataRoute && isAppPathRoute && !(isBlocking || isFallback)) {
10707
+ let prerender;
10708
+ if (experimentalPPR && appDir) {
10709
+ const htmlPath = import_path2.default.join(appDir, `${routeFileNoExt}.html`);
10710
+ const metaPath = import_path2.default.join(appDir, `${routeFileNoExt}.meta`);
10711
+ if (import_fs_extra3.default.existsSync(htmlPath) && import_fs_extra3.default.existsSync(metaPath)) {
10712
+ const meta = JSON.parse(await import_fs_extra3.default.readFile(metaPath, "utf8"));
10713
+ if ("postponed" in meta && typeof meta.postponed === "string") {
10714
+ prerender = meta.postponed;
10715
+ initialHeaders ??= {};
10716
+ initialHeaders["content-type"] = `application/x-nextjs-pre-render; state-length=${meta.postponed.length}`;
10717
+ const html = await import_fs_extra3.default.readFileSync(htmlPath, "utf8");
10718
+ prerender += html;
10719
+ }
10720
+ }
10721
+ if (!dataRoute?.endsWith(".rsc")) {
10722
+ throw new Error(
10723
+ `Invariant: unexpected output path for ${dataRoute} and PPR`
10724
+ );
10725
+ }
10726
+ if (!prefetchDataRoute?.endsWith(".prefetch.rsc")) {
10727
+ throw new Error(
10728
+ `Invariant: unexpected output path for ${prefetchDataRoute} and PPR`
10729
+ );
10730
+ }
10731
+ }
10732
+ if (prerender) {
10733
+ const contentType = initialHeaders?.["content-type"];
10734
+ if (!contentType) {
10735
+ throw new Error("Invariant: contentType can't be undefined");
10736
+ }
10737
+ htmlFsRef = new import_build_utils.FileBlob({ contentType, data: prerender });
10738
+ } else if (appDir && !dataRoute && isAppPathRoute && !(isBlocking || isFallback)) {
10662
10739
  const contentType = initialHeaders?.["content-type"];
10663
10740
  htmlFsRef = new import_build_utils.FileFsRef({
10664
10741
  fsPath: import_path2.default.join(appDir, `${routeFileNoExt}.body`),
@@ -10691,7 +10768,7 @@ var onPrerenderRoute = (prerenderRouteArgs) => (routeKey, {
10691
10768
  isFallback || isBlocking || isNotFound && !static404Page || !dataRoute ? null : new import_build_utils.FileFsRef({
10692
10769
  fsPath: import_path2.default.join(
10693
10770
  isAppPathRoute && !isOmittedOrNotFound && appDir ? appDir : pagesDir,
10694
- `${isOmittedOrNotFound ? localePrefixed404 ? addLocaleOrDefault("/404.html", routesManifest, locale) : "/404.html" : isAppPathRoute ? dataRoute : routeFileNoExt + ".json"}`
10771
+ `${isOmittedOrNotFound ? localePrefixed404 ? addLocaleOrDefault("/404.html", routesManifest, locale) : "/404.html" : isAppPathRoute ? prefetchDataRoute || dataRoute : routeFileNoExt + ".json"}`
10695
10772
  )
10696
10773
  })
10697
10774
  );
@@ -10714,11 +10791,10 @@ var onPrerenderRoute = (prerenderRouteArgs) => (routeKey, {
10714
10791
  origRouteFileNoExt
10715
10792
  );
10716
10793
  let lambda;
10717
- let outputPathData = null;
10718
- if (dataRoute) {
10719
- outputPathData = import_path2.default.posix.join(entryDirectory, dataRoute);
10794
+ function normalizeDataRoute(route) {
10795
+ let normalized = import_path2.default.posix.join(entryDirectory, route);
10720
10796
  if (nonDynamicSsg || isFallback || isOmitted) {
10721
- outputPathData = outputPathData.replace(
10797
+ normalized = normalized.replace(
10722
10798
  new RegExp(`${(0, import_escape_string_regexp.default)(origRouteFileNoExt)}.json$`),
10723
10799
  // ensure we escape "$" correctly while replacing as "$" is a special
10724
10800
  // character, we need to do double escaping as first is for the initial
@@ -10726,7 +10802,24 @@ var onPrerenderRoute = (prerenderRouteArgs) => (routeKey, {
10726
10802
  `${routeFileNoExt.replace(/\$/g, "$$$$")}.json`
10727
10803
  );
10728
10804
  }
10805
+ return normalized;
10806
+ }
10807
+ let outputPathData = null;
10808
+ if (dataRoute) {
10809
+ outputPathData = normalizeDataRoute(dataRoute);
10810
+ }
10811
+ let outputPathPrefetchData = null;
10812
+ if (prefetchDataRoute) {
10813
+ if (!experimentalPPR) {
10814
+ throw new Error(
10815
+ "Invariant: prefetchDataRoute can't be set without PPR"
10816
+ );
10817
+ }
10818
+ outputPathPrefetchData = normalizeDataRoute(prefetchDataRoute);
10819
+ } else if (experimentalPPR) {
10820
+ throw new Error("Invariant: expected to find prefetch data route PPR");
10729
10821
  }
10822
+ const outputPrerenderPathData = outputPathPrefetchData || outputPathData;
10730
10823
  if (isSharedLambdas) {
10731
10824
  const outputSrcPathPage = normalizeIndexOutput(
10732
10825
  import_path2.default.join(
@@ -10760,8 +10853,8 @@ var onPrerenderRoute = (prerenderRouteArgs) => (routeKey, {
10760
10853
  if (!canUsePreviewMode || routeKey === "/404" && !lambdas[outputPathPage]) {
10761
10854
  htmlFsRef.contentType = htmlContentType;
10762
10855
  prerenders[outputPathPage] = htmlFsRef;
10763
- if (outputPathData) {
10764
- prerenders[outputPathData] = jsonFsRef;
10856
+ if (outputPrerenderPathData) {
10857
+ prerenders[outputPrerenderPathData] = jsonFsRef;
10765
10858
  }
10766
10859
  }
10767
10860
  }
@@ -10797,10 +10890,22 @@ var onPrerenderRoute = (prerenderRouteArgs) => (routeKey, {
10797
10890
  const rscEnabled = !!routesManifest?.rsc;
10798
10891
  const rscVaryHeader = routesManifest?.rsc?.varyHeader || "RSC, Next-Router-State-Tree, Next-Router-Prefetch";
10799
10892
  const rscContentTypeHeader = routesManifest?.rsc?.contentTypeHeader || RSC_CONTENT_TYPE;
10893
+ const rscDidPostponeHeader = routesManifest?.rsc?.didPostponeHeader;
10800
10894
  let sourcePath;
10801
10895
  if (`/${outputPathPage}` !== srcRoute && srcRoute) {
10802
10896
  sourcePath = srcRoute;
10803
10897
  }
10898
+ let key = srcRoute || routeKey;
10899
+ if (key === "/") {
10900
+ key = "index";
10901
+ } else {
10902
+ if (!key.startsWith("/")) {
10903
+ throw new Error("Invariant: key doesn't start with /");
10904
+ }
10905
+ key = key.substring(1);
10906
+ }
10907
+ key = import_path2.default.posix.join(entryDirectory, key);
10908
+ const experimentalStreamingLambdaPath = experimentalStreamingLambdaPaths?.get(key);
10804
10909
  prerenders[outputPathPage] = new import_build_utils.Prerender({
10805
10910
  expiration: initialRevalidate,
10806
10911
  lambda,
@@ -10812,6 +10917,7 @@ var onPrerenderRoute = (prerenderRouteArgs) => (routeKey, {
10812
10917
  initialStatus,
10813
10918
  initialHeaders,
10814
10919
  sourcePath,
10920
+ experimentalStreamingLambdaPath,
10815
10921
  ...isNotFound ? {
10816
10922
  initialStatus: 404
10817
10923
  } : {},
@@ -10822,8 +10928,16 @@ var onPrerenderRoute = (prerenderRouteArgs) => (routeKey, {
10822
10928
  }
10823
10929
  } : {}
10824
10930
  });
10825
- if (outputPathData) {
10826
- prerenders[outputPathData] = new import_build_utils.Prerender({
10931
+ if (outputPrerenderPathData) {
10932
+ let normalizedPathData = outputPrerenderPathData;
10933
+ if ((srcRoute === "/" || srcRoute == "/index") && outputPrerenderPathData.endsWith(RSC_PREFETCH_SUFFIX)) {
10934
+ delete lambdas[normalizedPathData];
10935
+ normalizedPathData = normalizedPathData.replace(
10936
+ /([^/]+\.prefetch\.rsc)$/,
10937
+ "__$1"
10938
+ );
10939
+ }
10940
+ prerenders[normalizedPathData] = new import_build_utils.Prerender({
10827
10941
  expiration: initialRevalidate,
10828
10942
  lambda,
10829
10943
  allowQuery,
@@ -10837,7 +10951,8 @@ var onPrerenderRoute = (prerenderRouteArgs) => (routeKey, {
10837
10951
  ...rscEnabled ? {
10838
10952
  initialHeaders: {
10839
10953
  "content-type": rscContentTypeHeader,
10840
- vary: rscVaryHeader
10954
+ vary: rscVaryHeader,
10955
+ ...experimentalPPR && rscDidPostponeHeader ? { [rscDidPostponeHeader]: "1" } : {}
10841
10956
  }
10842
10957
  } : {}
10843
10958
  });
@@ -11375,6 +11490,18 @@ async function getServerlessPages(params) {
11375
11490
  }
11376
11491
  return { pages, appPaths: normalizedAppPaths };
11377
11492
  }
11493
+ function normalizePrefetches(prefetches) {
11494
+ const updatedPrefetches = {};
11495
+ for (const key in prefetches) {
11496
+ if (key === "index.prefetch.rsc") {
11497
+ const newKey = key.replace(/([^/]+\.prefetch\.rsc)$/, "__$1");
11498
+ updatedPrefetches[newKey] = prefetches[key];
11499
+ } else {
11500
+ updatedPrefetches[key] = prefetches[key];
11501
+ }
11502
+ }
11503
+ return updatedPrefetches;
11504
+ }
11378
11505
 
11379
11506
  // src/create-serverless-config.ts
11380
11507
  function getCustomData(importName, target) {
@@ -11865,18 +11992,18 @@ async function serverBuild({
11865
11992
  inversedAppPathManifest[appPathRoutesManifest[ogRoute]] = ogRoute;
11866
11993
  }
11867
11994
  }
11995
+ const experimental = {
11996
+ ppr: requiredServerFilesManifest.config.experimental?.ppr === true
11997
+ };
11868
11998
  let appRscPrefetches = {};
11869
11999
  let appBuildTraces = {};
11870
12000
  let appDir = null;
11871
12001
  if (appPathRoutesManifest) {
11872
12002
  appDir = import_path4.default.join(pagesDir, "../app");
11873
12003
  appBuildTraces = await (0, import_build_utils2.glob)("**/*.js.nft.json", appDir);
11874
- appRscPrefetches = await (0, import_build_utils2.glob)(`**/*${RSC_PREFETCH_SUFFIX}`, appDir);
12004
+ appRscPrefetches = experimental.ppr ? {} : await (0, import_build_utils2.glob)(`**/*${RSC_PREFETCH_SUFFIX}`, appDir);
11875
12005
  const rscContentTypeHeader = routesManifest?.rsc?.contentTypeHeader || RSC_CONTENT_TYPE;
11876
- if (appRscPrefetches["index.prefetch.rsc"]) {
11877
- appRscPrefetches["__index.prefetch.rsc"] = appRscPrefetches["index.prefetch.rsc"];
11878
- delete appRscPrefetches["index.prefetch.rsc"];
11879
- }
12006
+ appRscPrefetches = normalizePrefetches(appRscPrefetches);
11880
12007
  for (const value of Object.values(appRscPrefetches)) {
11881
12008
  if (!value.contentType) {
11882
12009
  value.contentType = rscContentTypeHeader;
@@ -11943,6 +12070,16 @@ async function serverBuild({
11943
12070
  if (lambdaPages["404.js"]) {
11944
12071
  internalPages.push("404.js");
11945
12072
  }
12073
+ const experimentalPPRRoutes = /* @__PURE__ */ new Set();
12074
+ for (const [route, { experimentalPPR }] of [
12075
+ ...Object.entries(prerenderManifest.staticRoutes),
12076
+ ...Object.entries(prerenderManifest.blockingFallbackRoutes),
12077
+ ...Object.entries(prerenderManifest.fallbackRoutes)
12078
+ ]) {
12079
+ if (!experimentalPPR)
12080
+ continue;
12081
+ experimentalPPRRoutes.add(route);
12082
+ }
11946
12083
  const prerenderRoutes = /* @__PURE__ */ new Set([
11947
12084
  ...canUsePreviewMode ? omittedPrerenderRoutes : [],
11948
12085
  ...Object.keys(prerenderManifest.blockingFallbackRoutes),
@@ -11952,6 +12089,7 @@ async function serverBuild({
11952
12089
  return staticRoute.srcRoute || route;
11953
12090
  })
11954
12091
  ]);
12092
+ const experimentalStreamingLambdaPaths = /* @__PURE__ */ new Map();
11955
12093
  if (hasLambdas) {
11956
12094
  const initialTracingLabel = "Traced Next.js server files in";
11957
12095
  console.time(initialTracingLabel);
@@ -12197,8 +12335,8 @@ async function serverBuild({
12197
12335
  "utf8"
12198
12336
  );
12199
12337
  let launcher = launcherData.replace(
12200
- "conf: __NEXT_CONFIG__",
12201
- `conf: ${JSON.stringify({
12338
+ "const conf = __NEXT_CONFIG__",
12339
+ `const conf = ${JSON.stringify({
12202
12340
  ...requiredServerFilesManifest.config,
12203
12341
  distDir: import_path4.default.relative(
12204
12342
  projectDir,
@@ -12345,6 +12483,7 @@ async function serverBuild({
12345
12483
  prerenderRoutes,
12346
12484
  pageTraces,
12347
12485
  compressedPages,
12486
+ experimentalPPRRoutes: void 0,
12348
12487
  tracedPseudoLayer: tracedPseudoLayer.pseudoLayer,
12349
12488
  initialPseudoLayer,
12350
12489
  lambdaCompressedByteLimit,
@@ -12363,6 +12502,7 @@ async function serverBuild({
12363
12502
  prerenderRoutes,
12364
12503
  pageTraces,
12365
12504
  compressedPages,
12505
+ experimentalPPRRoutes,
12366
12506
  tracedPseudoLayer: tracedPseudoLayer.pseudoLayer,
12367
12507
  initialPseudoLayer,
12368
12508
  lambdaCompressedByteLimit,
@@ -12378,6 +12518,7 @@ async function serverBuild({
12378
12518
  prerenderRoutes,
12379
12519
  pageTraces,
12380
12520
  compressedPages,
12521
+ experimentalPPRRoutes: void 0,
12381
12522
  tracedPseudoLayer: tracedPseudoLayer.pseudoLayer,
12382
12523
  initialPseudoLayer,
12383
12524
  lambdaCompressedByteLimit,
@@ -12386,7 +12527,7 @@ async function serverBuild({
12386
12527
  pageExtensions
12387
12528
  });
12388
12529
  for (const group of appRouterLambdaGroups) {
12389
- if (!group.isPrerenders) {
12530
+ if (!group.isPrerenders || group.isExperimentalPPR) {
12390
12531
  group.isStreaming = true;
12391
12532
  }
12392
12533
  group.isAppRouter = true;
@@ -12406,6 +12547,7 @@ async function serverBuild({
12406
12547
  prerenderRoutes,
12407
12548
  pageTraces,
12408
12549
  compressedPages,
12550
+ experimentalPPRRoutes: void 0,
12409
12551
  tracedPseudoLayer: tracedPseudoLayer.pseudoLayer,
12410
12552
  initialPseudoLayer,
12411
12553
  initialPseudoLayerUncompressed: uncompressedInitialSize,
@@ -12520,7 +12662,7 @@ async function serverBuild({
12520
12662
  [import_path4.default.join(import_path4.default.relative(baseDir, projectDir), "___next_launcher.cjs")]: new import_build_utils2.FileBlob({ data: group.isAppRouter ? appLauncher : launcher })
12521
12663
  };
12522
12664
  const operationType = getOperationType({ group, prerenderManifest });
12523
- const lambda = await createLambdaFromPseudoLayers({
12665
+ const options = {
12524
12666
  files: {
12525
12667
  ...launcherFiles,
12526
12668
  ...updatedManifestFiles
@@ -12536,7 +12678,19 @@ async function serverBuild({
12536
12678
  maxDuration: group.maxDuration,
12537
12679
  isStreaming: group.isStreaming,
12538
12680
  nextVersion
12539
- });
12681
+ };
12682
+ const lambda = await createLambdaFromPseudoLayers(options);
12683
+ const isPPR = experimental.ppr && group.isAppRouter && !group.isAppRouteHandler;
12684
+ let revalidate;
12685
+ if (isPPR) {
12686
+ if (isPPR && !options.isStreaming) {
12687
+ throw new Error("Invariant: PPR lambda isn't streaming");
12688
+ }
12689
+ revalidate = await createLambdaFromPseudoLayers({
12690
+ ...options,
12691
+ isStreaming: false
12692
+ });
12693
+ }
12540
12694
  for (const page of group.pages) {
12541
12695
  const pageNoExt = page.replace(/\.js$/, "");
12542
12696
  let isPrerender = prerenderRoutes.has(
@@ -12549,10 +12703,25 @@ async function serverBuild({
12549
12703
  );
12550
12704
  });
12551
12705
  }
12552
- const outputName = normalizeIndexOutput(
12706
+ let outputName = normalizeIndexOutput(
12553
12707
  import_path4.default.posix.join(entryDirectory, pageNoExt),
12554
12708
  true
12555
12709
  );
12710
+ if (isPPR) {
12711
+ if (!revalidate) {
12712
+ throw new Error("Invariant: PPR lambda isn't set");
12713
+ }
12714
+ outputName = import_path4.default.posix.join(entryDirectory, pageNoExt);
12715
+ lambdas[outputName] = revalidate;
12716
+ const pprOutputName = import_path4.default.posix.join(
12717
+ entryDirectory,
12718
+ "/_next/postponed/resume",
12719
+ pageNoExt
12720
+ );
12721
+ lambdas[pprOutputName] = lambda;
12722
+ experimentalStreamingLambdaPaths.set(outputName, pprOutputName);
12723
+ continue;
12724
+ }
12556
12725
  if (i18n && !isPrerender && !group.isAppRouter && (!isCorrectLocaleAPIRoutes || !(pageNoExt === "api" || pageNoExt.startsWith("api/")))) {
12557
12726
  for (const locale of i18n.locales) {
12558
12727
  lambdas[normalizeIndexOutput(
@@ -12576,6 +12745,7 @@ async function serverBuild({
12576
12745
  pagesDir,
12577
12746
  pageLambdaMap: {},
12578
12747
  lambdas,
12748
+ experimentalStreamingLambdaPaths,
12579
12749
  prerenders,
12580
12750
  entryDirectory,
12581
12751
  routesManifest,
@@ -12590,25 +12760,38 @@ async function serverBuild({
12590
12760
  isCorrectNotFoundRoutes,
12591
12761
  isEmptyAllowQueryForPrendered
12592
12762
  });
12593
- Object.keys(prerenderManifest.staticRoutes).forEach(
12594
- (route) => prerenderRoute(route, {})
12763
+ await Promise.all(
12764
+ Object.keys(prerenderManifest.staticRoutes).map(
12765
+ (route) => prerenderRoute(route, {})
12766
+ )
12595
12767
  );
12596
- Object.keys(prerenderManifest.fallbackRoutes).forEach(
12597
- (route) => prerenderRoute(route, { isFallback: true })
12768
+ await Promise.all(
12769
+ Object.keys(prerenderManifest.fallbackRoutes).map(
12770
+ (route) => prerenderRoute(route, { isFallback: true })
12771
+ )
12598
12772
  );
12599
- Object.keys(prerenderManifest.blockingFallbackRoutes).forEach(
12600
- (route) => prerenderRoute(route, { isBlocking: true })
12773
+ await Promise.all(
12774
+ Object.keys(prerenderManifest.blockingFallbackRoutes).map(
12775
+ (route) => prerenderRoute(route, { isBlocking: true })
12776
+ )
12601
12777
  );
12602
12778
  if (static404Page && canUsePreviewMode) {
12603
- omittedPrerenderRoutes.forEach((route) => {
12604
- prerenderRoute(route, { isOmitted: true });
12605
- });
12779
+ await Promise.all(
12780
+ [...omittedPrerenderRoutes].map((route) => {
12781
+ return prerenderRoute(route, { isOmitted: true });
12782
+ })
12783
+ );
12606
12784
  }
12607
12785
  prerenderRoutes.forEach((route) => {
12786
+ if (experimentalPPRRoutes.has(route))
12787
+ return;
12608
12788
  if (routesManifest?.i18n) {
12609
12789
  route = normalizeLocalePath(route, routesManifest.i18n.locales).pathname;
12610
12790
  }
12611
- delete lambdas[import_path4.default.posix.join(".", entryDirectory, route === "/" ? "index" : route)];
12791
+ delete lambdas[normalizeIndexOutput(
12792
+ import_path4.default.posix.join("./", entryDirectory, route === "/" ? "/index" : route),
12793
+ true
12794
+ )];
12612
12795
  });
12613
12796
  const middleware = await getMiddlewareBundle({
12614
12797
  config,
@@ -12631,7 +12814,8 @@ async function serverBuild({
12631
12814
  canUsePreviewMode,
12632
12815
  prerenderManifest.bypassToken || "",
12633
12816
  true,
12634
- middleware.dynamicRouteMap
12817
+ middleware.dynamicRouteMap,
12818
+ experimental.ppr
12635
12819
  ).then(
12636
12820
  (arr) => localizeDynamicRoutes(
12637
12821
  arr,
@@ -12771,20 +12955,20 @@ async function serverBuild({
12771
12955
  }
12772
12956
  if (appPathRoutesManifest) {
12773
12957
  const edgeFunctions = middleware.edgeFunctions;
12774
- for (let route of Object.values(appPathRoutesManifest)) {
12958
+ for (const route of Object.values(appPathRoutesManifest)) {
12775
12959
  const ogRoute = inversedAppPathManifest[route];
12776
12960
  if (ogRoute.endsWith("/route")) {
12777
12961
  continue;
12778
12962
  }
12779
- route = normalizeIndexOutput(
12963
+ const pathname = normalizeIndexOutput(
12780
12964
  import_path4.default.posix.join("./", entryDirectory, route === "/" ? "/index" : route),
12781
12965
  true
12782
12966
  );
12783
- if (lambdas[route]) {
12784
- lambdas[`${route}.rsc`] = lambdas[route];
12967
+ if (lambdas[pathname]) {
12968
+ lambdas[`${pathname}.rsc`] = lambdas[pathname];
12785
12969
  }
12786
- if (edgeFunctions[route]) {
12787
- edgeFunctions[`${route}.rsc`] = edgeFunctions[route];
12970
+ if (edgeFunctions[pathname]) {
12971
+ edgeFunctions[`${pathname}.rsc`] = edgeFunctions[pathname];
12788
12972
  }
12789
12973
  }
12790
12974
  }
@@ -12797,6 +12981,9 @@ async function serverBuild({
12797
12981
  ...value,
12798
12982
  metadata: value.metadata ?? {}
12799
12983
  })) : [];
12984
+ if (experimental.ppr && !rscPrefetchHeader) {
12985
+ throw new Error("Invariant: cannot use PPR without 'rsc.prefetchHeader'");
12986
+ }
12800
12987
  return {
12801
12988
  wildcard: wildcardConfig,
12802
12989
  images: getImagesConfig(imagesManifest),
@@ -13079,7 +13266,7 @@ async function serverBuild({
13079
13266
  check: true
13080
13267
  }
13081
13268
  ] : [],
13082
- ...rscPrefetchHeader ? [
13269
+ ...rscPrefetchHeader && !experimental.ppr ? [
13083
13270
  {
13084
13271
  src: import_path4.default.posix.join(
13085
13272
  "/",
@@ -13102,7 +13289,11 @@ async function serverBuild({
13102
13289
  entryDirectory,
13103
13290
  `/(.+?)${RSC_PREFETCH_SUFFIX}(?:/)?$`
13104
13291
  )}`,
13105
- dest: import_path4.default.posix.join("/", entryDirectory, "/$1.rsc"),
13292
+ dest: import_path4.default.posix.join(
13293
+ "/",
13294
+ entryDirectory,
13295
+ `/$1${experimental.ppr ? RSC_PREFETCH_SUFFIX : ".rsc"}`
13296
+ ),
13106
13297
  has: [
13107
13298
  {
13108
13299
  type: "header",
@@ -13273,8 +13464,6 @@ async function serverBuild({
13273
13464
  continue: true,
13274
13465
  important: true
13275
13466
  },
13276
- // TODO: remove below workaround when `/` is allowed to be output
13277
- // different than `/index`
13278
13467
  {
13279
13468
  src: import_path4.default.posix.join("/", entryDirectory, "/index"),
13280
13469
  headers: {
@@ -14460,7 +14649,8 @@ More info: http://err.sh/vercel/vercel/next-functions-config-optimized-lambdas`
14460
14649
  lambdaCompressedByteLimit,
14461
14650
  // internal pages are already referenced in traces for serverless
14462
14651
  // like builds
14463
- internalPages: []
14652
+ internalPages: [],
14653
+ experimentalPPRRoutes: void 0
14464
14654
  });
14465
14655
  const initialApiLambdaGroups = await getPageLambdaGroups({
14466
14656
  entryPath,
@@ -14474,7 +14664,8 @@ More info: http://err.sh/vercel/vercel/next-functions-config-optimized-lambdas`
14474
14664
  initialPseudoLayer: { pseudoLayer: {}, pseudoLayerBytes: 0 },
14475
14665
  initialPseudoLayerUncompressed: 0,
14476
14666
  lambdaCompressedByteLimit,
14477
- internalPages: []
14667
+ internalPages: [],
14668
+ experimentalPPRRoutes: void 0
14478
14669
  });
14479
14670
  for (const group of initialApiLambdaGroups) {
14480
14671
  group.isApiLambda = true;
@@ -14882,6 +15073,7 @@ More info: http://err.sh/vercel/vercel/next-functions-config-optimized-lambdas`
14882
15073
  static404Page,
14883
15074
  pageLambdaMap,
14884
15075
  lambdas,
15076
+ experimentalStreamingLambdaPaths: void 0,
14885
15077
  isServerMode,
14886
15078
  prerenders,
14887
15079
  entryDirectory,
@@ -14909,20 +15101,40 @@ More info: http://err.sh/vercel/vercel/next-functions-config-optimized-lambdas`
14909
15101
  [
14910
15102
  ...Object.entries(prerenderManifest.fallbackRoutes),
14911
15103
  ...Object.entries(prerenderManifest.blockingFallbackRoutes)
14912
- ].forEach(([, { dataRouteRegex, dataRoute }]) => {
14913
- if (!dataRoute || !dataRouteRegex)
14914
- return;
14915
- dataRoutes.push({
14916
- // Next.js provided data route regex
14917
- src: dataRouteRegex.replace(
14918
- /^\^/,
14919
- `^${appMountPrefixNoTrailingSlash}`
14920
- ),
14921
- // Location of lambda in builder output
14922
- dest: import_path5.default.posix.join(entryDirectory, dataRoute),
14923
- check: true
14924
- });
14925
- });
15104
+ ].forEach(
15105
+ ([
15106
+ ,
15107
+ {
15108
+ dataRouteRegex,
15109
+ dataRoute,
15110
+ prefetchDataRouteRegex,
15111
+ prefetchDataRoute
15112
+ }
15113
+ ]) => {
15114
+ if (!dataRoute || !dataRouteRegex)
15115
+ return;
15116
+ dataRoutes.push({
15117
+ // Next.js provided data route regex
15118
+ src: dataRouteRegex.replace(
15119
+ /^\^/,
15120
+ `^${appMountPrefixNoTrailingSlash}`
15121
+ ),
15122
+ // Location of lambda in builder output
15123
+ dest: import_path5.default.posix.join(entryDirectory, dataRoute),
15124
+ check: true
15125
+ });
15126
+ if (!prefetchDataRoute || !prefetchDataRouteRegex)
15127
+ return;
15128
+ dataRoutes.push({
15129
+ src: prefetchDataRouteRegex.replace(
15130
+ /^\^/,
15131
+ `^${appMountPrefixNoTrailingSlash}`
15132
+ ),
15133
+ dest: import_path5.default.posix.join(entryDirectory, prefetchDataRoute),
15134
+ check: true
15135
+ });
15136
+ }
15137
+ );
14926
15138
  }
14927
15139
  }
14928
15140
  if (!isSharedLambdas) {
@@ -12,20 +12,23 @@ if (process.env.NODE_ENV !== "production" && region !== "dev1") {
12
12
  }
13
13
  // @preserve pre-next-server-target
14
14
  const NextServer = require("__NEXT_SERVER_PATH__").default;
15
+ const conf = __NEXT_CONFIG__;
15
16
  const nextServer = new NextServer({
16
- // @ts-ignore __NEXT_CONFIG__ value is injected
17
- conf: __NEXT_CONFIG__,
17
+ conf,
18
18
  dir: ".",
19
19
  minimalMode: true,
20
20
  customServer: false
21
21
  });
22
- const requestHandler = nextServer.getRequestHandler();
23
- module.exports = async (req, res) => {
22
+ const serve = (handler) => async (req, res) => {
24
23
  try {
25
24
  // @preserve entryDirectory handler
26
- await requestHandler(req, res);
25
+ await handler(req, res);
27
26
  } catch (err) {
28
27
  console.error(err);
29
28
  process.exit(1);
30
29
  }
31
30
  };
31
+ module.exports = serve(nextServer.getRequestHandler());
32
+ if (conf.experimental?.ppr && "getRequestHandlerWithMetadata" in nextServer && typeof nextServer.getRequestHandlerWithMetadata === "function") {
33
+ module.exports.getRequestHandlerWithMetadata = (metadata) => serve(nextServer.getRequestHandlerWithMetadata(metadata));
34
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/next",
3
- "version": "4.0.11",
3
+ "version": "4.0.13",
4
4
  "license": "Apache-2.0",
5
5
  "main": "./dist/index",
6
6
  "homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
@@ -30,7 +30,7 @@
30
30
  "@types/semver": "6.0.0",
31
31
  "@types/text-table": "0.2.1",
32
32
  "@types/webpack-sources": "3.2.0",
33
- "@vercel/build-utils": "7.2.2",
33
+ "@vercel/build-utils": "7.2.3",
34
34
  "@vercel/routing-utils": "3.1.0",
35
35
  "async-sema": "3.0.1",
36
36
  "buffer-crc32": "0.2.13",