@vercel/next 4.0.0 → 4.0.2

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.
@@ -39,11 +39,14 @@ async function serverBuild({ dynamicPages, pagesDir, config = {}, functionsConfi
39
39
  inversedAppPathManifest[appPathRoutesManifest[ogRoute]] = ogRoute;
40
40
  }
41
41
  }
42
+ const APP_PREFETCH_SUFFIX = '.prefetch.rsc';
43
+ let appRscPrefetches = {};
42
44
  let appBuildTraces = {};
43
45
  let appDir = null;
44
46
  if (appPathRoutesManifest) {
45
47
  appDir = path_1.default.join(pagesDir, '../app');
46
48
  appBuildTraces = await (0, build_utils_1.glob)('**/*.js.nft.json', appDir);
49
+ appRscPrefetches = await (0, build_utils_1.glob)(`**/*${APP_PREFETCH_SUFFIX}`, appDir);
47
50
  }
48
51
  const isCorrectNotFoundRoutes = semver_1.default.gte(nextVersion, CORRECT_NOT_FOUND_ROUTES_VERSION);
49
52
  const isCorrectMiddlewareOrder = semver_1.default.gte(nextVersion, CORRECT_MIDDLEWARE_ORDER_VERSION);
@@ -203,10 +206,17 @@ async function serverBuild({ dynamicPages, pagesDir, config = {}, functionsConfi
203
206
  // for notFound GS(S)P support
204
207
  if (i18n) {
205
208
  for (const locale of i18n.locales) {
206
- const static404File = staticPages[path_1.default.posix.join(entryDirectory, locale, '/404')] ||
207
- new build_utils_1.FileFsRef({
209
+ let static404File = staticPages[path_1.default.posix.join(entryDirectory, locale, '/404')];
210
+ if (!static404File) {
211
+ static404File = new build_utils_1.FileFsRef({
208
212
  fsPath: path_1.default.join(pagesDir, locale, '/404.html'),
209
213
  });
214
+ if (!fs_extra_1.default.existsSync(static404File.fsPath)) {
215
+ static404File = new build_utils_1.FileFsRef({
216
+ fsPath: path_1.default.join(pagesDir, '/404.html'),
217
+ });
218
+ }
219
+ }
210
220
  requiredFiles[path_1.default.relative(baseDir, static404File.fsPath)] =
211
221
  static404File;
212
222
  }
@@ -619,7 +629,25 @@ async function serverBuild({ dynamicPages, pagesDir, config = {}, functionsConfi
619
629
  });
620
630
  const isNextDataServerResolving = middleware.staticRoutes.length > 0 &&
621
631
  semver_1.default.gte(nextVersion, NEXT_DATA_MIDDLEWARE_RESOLVING_VERSION);
622
- const dynamicRoutes = await (0, utils_1.getDynamicRoutes)(entryPath, entryDirectory, dynamicPages, false, routesManifest, omittedPrerenderRoutes, canUsePreviewMode, prerenderManifest.bypassToken || '', true, middleware.dynamicRouteMap, inversedAppPathManifest).then(arr => (0, utils_1.localizeDynamicRoutes)(arr, dynamicPrefix, entryDirectory, staticPages, prerenderManifest, routesManifest, true, isCorrectLocaleAPIRoutes, inversedAppPathManifest));
632
+ const dynamicRoutes = await (0, utils_1.getDynamicRoutes)(entryPath, entryDirectory, dynamicPages, false, routesManifest, omittedPrerenderRoutes, canUsePreviewMode, prerenderManifest.bypassToken || '', true, middleware.dynamicRouteMap).then(arr => (0, utils_1.localizeDynamicRoutes)(arr, dynamicPrefix, entryDirectory, staticPages, prerenderManifest, routesManifest, true, isCorrectLocaleAPIRoutes, inversedAppPathManifest));
633
+ const pagesPlaceholderRscEntries = {};
634
+ if (appDir) {
635
+ // since we attempt to rewrite all paths to an .rsc variant,
636
+ // we need to create dummy rsc outputs for all pages entries
637
+ // this is so that an RSC request to a `pages` entry will match
638
+ // rather than falling back to a catchall `app` entry
639
+ // on the nextjs side, invalid RSC response payloads will correctly trigger an mpa navigation
640
+ const pagesManifest = path_1.default.join(entryPath, outputDirectory, `server/pages-manifest.json`);
641
+ const pagesData = await fs_extra_1.default.readJSON(pagesManifest);
642
+ const pagesEntries = Object.keys(pagesData);
643
+ for (const page of pagesEntries) {
644
+ const pathName = page.startsWith('/') ? page.slice(1) : page;
645
+ pagesPlaceholderRscEntries[`${pathName}.rsc`] = new build_utils_1.FileBlob({
646
+ data: '{}',
647
+ contentType: 'application/json',
648
+ });
649
+ }
650
+ }
623
651
  const { staticFiles, publicDirectoryFiles, staticDirectoryFiles } = await (0, utils_1.getStaticFiles)(entryPath, entryDirectory, outputDirectory);
624
652
  const normalizeNextDataRoute = (isOverride = false) => {
625
653
  return isNextDataServerResolving
@@ -705,7 +733,7 @@ async function serverBuild({ dynamicPages, pagesDir, config = {}, functionsConfi
705
733
  if (ogRoute.endsWith('/route')) {
706
734
  continue;
707
735
  }
708
- route = path_1.default.posix.join('./', entryDirectory, route === '/' ? '/index' : route);
736
+ route = (0, utils_1.normalizeIndexOutput)(path_1.default.posix.join('./', entryDirectory, route === '/' ? '/index' : route), true);
709
737
  if (lambdas[route]) {
710
738
  lambdas[`${route}.rsc`] = lambdas[route];
711
739
  }
@@ -715,6 +743,7 @@ async function serverBuild({ dynamicPages, pagesDir, config = {}, functionsConfi
715
743
  }
716
744
  }
717
745
  const rscHeader = routesManifest.rsc?.header?.toLowerCase() || '__rsc__';
746
+ const rscPrefetchHeader = routesManifest.rsc?.prefetchHeader?.toLowerCase();
718
747
  const rscVaryHeader = routesManifest?.rsc?.varyHeader ||
719
748
  'RSC, Next-Router-State-Tree, Next-Router-Prefetch';
720
749
  const appNotFoundPath = path_1.default.posix.join('.', entryDirectory, '_not-found');
@@ -724,6 +753,8 @@ async function serverBuild({ dynamicPages, pagesDir, config = {}, functionsConfi
724
753
  output: {
725
754
  ...publicDirectoryFiles,
726
755
  ...lambdas,
756
+ ...appRscPrefetches,
757
+ ...pagesPlaceholderRscEntries,
727
758
  // Prerenders may override Lambdas -- this is an intentional behavior.
728
759
  ...prerenders,
729
760
  ...staticPages,
@@ -905,6 +936,36 @@ async function serverBuild({ dynamicPages, pagesDir, config = {}, functionsConfi
905
936
  ...(!isCorrectMiddlewareOrder ? middleware.staticRoutes : []),
906
937
  ...(appDir
907
938
  ? [
939
+ ...(rscPrefetchHeader
940
+ ? [
941
+ {
942
+ src: `^${path_1.default.posix.join('/', entryDirectory, '/')}`,
943
+ has: [
944
+ {
945
+ type: 'header',
946
+ key: rscPrefetchHeader,
947
+ },
948
+ ],
949
+ dest: path_1.default.posix.join('/', entryDirectory, '/index.prefetch.rsc'),
950
+ headers: { vary: rscVaryHeader },
951
+ continue: true,
952
+ override: true,
953
+ },
954
+ {
955
+ src: `^${path_1.default.posix.join('/', entryDirectory, '/((?!.+\\.rsc).+?)(?:/)?$')}`,
956
+ has: [
957
+ {
958
+ type: 'header',
959
+ key: rscPrefetchHeader,
960
+ },
961
+ ],
962
+ dest: path_1.default.posix.join('/', entryDirectory, `/$1${APP_PREFETCH_SUFFIX}`),
963
+ headers: { vary: rscVaryHeader },
964
+ continue: true,
965
+ override: true,
966
+ },
967
+ ]
968
+ : []),
908
969
  {
909
970
  src: `^${path_1.default.posix.join('/', entryDirectory, '/')}`,
910
971
  has: [
@@ -960,17 +1021,45 @@ async function serverBuild({ dynamicPages, pagesDir, config = {}, functionsConfi
960
1021
  },
961
1022
  ]
962
1023
  : []),
1024
+ ...(rscPrefetchHeader
1025
+ ? [
1026
+ {
1027
+ src: path_1.default.posix.join('/', entryDirectory, `/index${APP_PREFETCH_SUFFIX}`),
1028
+ dest: path_1.default.posix.join('/', entryDirectory, '/index.rsc'),
1029
+ has: [
1030
+ {
1031
+ type: 'header',
1032
+ key: rscPrefetchHeader,
1033
+ },
1034
+ ],
1035
+ continue: true,
1036
+ override: true,
1037
+ },
1038
+ {
1039
+ src: `^${path_1.default.posix.join('/', entryDirectory, `/(.+?)${APP_PREFETCH_SUFFIX}(?:/)?$`)}`,
1040
+ dest: path_1.default.posix.join('/', entryDirectory, '/$1.rsc'),
1041
+ has: [
1042
+ {
1043
+ type: 'header',
1044
+ key: rscPrefetchHeader,
1045
+ },
1046
+ ],
1047
+ continue: true,
1048
+ override: true,
1049
+ },
1050
+ ]
1051
+ : []),
963
1052
  // These need to come before handle: miss or else they are grouped
964
1053
  // with that routing section
965
1054
  ...afterFilesRewrites,
966
- // make sure 404 page is used when a directory is matched without
967
- // an index page
968
1055
  { handle: 'resource' },
969
1056
  ...fallbackRewrites,
1057
+ // make sure 404 page is used when a directory is matched without
1058
+ // an index page
970
1059
  { src: path_1.default.posix.join('/', entryDirectory, '.*'), status: 404 },
1060
+ { handle: 'miss' },
971
1061
  // We need to make sure to 404 for /_next after handle: miss since
972
1062
  // handle: miss is called before rewrites and to prevent rewriting /_next
973
- { handle: 'miss' },
974
1063
  {
975
1064
  src: path_1.default.posix.join('/', entryDirectory, '_next/static/(?:[^/]+/pages|pages|chunks|runtime|css|image|media)/.+'),
976
1065
  status: 404,
package/dist/utils.js CHANGED
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.isApiPage = exports.getOperationType = exports.upgradeMiddlewareManifest = exports.getMiddlewareManifest = exports.getFunctionsConfigManifest = exports.getMiddlewareBundle = exports.getSourceFilePathFromPage = exports.isDynamicRoute = exports.normalizePage = exports.getImagesConfig = exports.getNextConfig = exports.normalizePackageJson = exports.validateEntrypoint = exports.excludeFiles = exports.getPrivateOutputs = exports.updateRouteSrc = exports.getNextServerPath = exports.normalizeIndexOutput = exports.getStaticFiles = exports.onPrerenderRoute = exports.onPrerenderRouteInitial = exports.detectLambdaLimitExceeding = exports.outputFunctionFileSizeInfo = exports.getPageLambdaGroups = exports.MAX_UNCOMPRESSED_LAMBDA_SIZE = exports.addLocaleOrDefault = exports.normalizeLocalePath = exports.getPrerenderManifest = exports.getRequiredServerFilesManifest = exports.getExportStatus = exports.getExportIntent = exports.createLambdaFromPseudoLayers = exports.createPseudoLayer = exports.ExperimentalTraceVersion = exports.collectTracedFiles = exports.getFilesMapFromReasons = exports.filterStaticPages = exports.getImagesManifest = exports.localizeDynamicRoutes = exports.getDynamicRoutes = exports.getRoutesManifest = exports.prettyBytes = exports.MIB = exports.KIB = void 0;
29
+ exports.isApiPage = exports.getOperationType = exports.upgradeMiddlewareManifest = exports.getMiddlewareManifest = exports.getFunctionsConfigManifest = exports.getMiddlewareBundle = exports.normalizeEdgeFunctionPath = exports.getSourceFilePathFromPage = exports.isDynamicRoute = exports.normalizePage = exports.getImagesConfig = exports.getNextConfig = exports.normalizePackageJson = exports.validateEntrypoint = exports.excludeFiles = exports.getPrivateOutputs = exports.updateRouteSrc = exports.getNextServerPath = exports.normalizeIndexOutput = exports.getStaticFiles = exports.onPrerenderRoute = exports.onPrerenderRouteInitial = exports.detectLambdaLimitExceeding = exports.outputFunctionFileSizeInfo = exports.getPageLambdaGroups = exports.MAX_UNCOMPRESSED_LAMBDA_SIZE = exports.addLocaleOrDefault = exports.normalizeLocalePath = exports.getPrerenderManifest = exports.getRequiredServerFilesManifest = exports.getExportStatus = exports.getExportIntent = exports.createLambdaFromPseudoLayers = exports.createPseudoLayer = exports.ExperimentalTraceVersion = exports.collectTracedFiles = exports.getFilesMapFromReasons = exports.filterStaticPages = exports.getImagesManifest = exports.localizeDynamicRoutes = exports.getDynamicRoutes = exports.getRoutesManifest = exports.prettyBytes = exports.MIB = exports.KIB = void 0;
30
30
  const build_utils_1 = require("@vercel/build-utils");
31
31
  const async_sema_1 = require("async-sema");
32
32
  const buffer_crc32_1 = __importDefault(require("buffer-crc32"));
@@ -194,7 +194,7 @@ async function getRoutesManifest(entryPath, outputDirectory, nextVersion) {
194
194
  return routesManifest;
195
195
  }
196
196
  exports.getRoutesManifest = getRoutesManifest;
197
- async function getDynamicRoutes(entryPath, entryDirectory, dynamicPages, isDev, routesManifest, omittedRoutes, canUsePreviewMode, bypassToken, isServerMode, dynamicMiddlewareRouteMap, appPathRoutesManifest) {
197
+ async function getDynamicRoutes(entryPath, entryDirectory, dynamicPages, isDev, routesManifest, omittedRoutes, canUsePreviewMode, bypassToken, isServerMode, dynamicMiddlewareRouteMap) {
198
198
  if (routesManifest) {
199
199
  switch (routesManifest.version) {
200
200
  case 1:
@@ -253,13 +253,11 @@ async function getDynamicRoutes(entryPath, entryDirectory, dynamicPages, isDev,
253
253
  },
254
254
  ];
255
255
  }
256
- if (appPathRoutesManifest?.[page]) {
257
- routes.push({
258
- ...route,
259
- src: route.src.replace(new RegExp((0, escape_string_regexp_1.default)('(?:/)?$')), '(?:\\.rsc)(?:/)?$'),
260
- dest: route.dest?.replace(/($|\?)/, '.rsc$1'),
261
- });
262
- }
256
+ routes.push({
257
+ ...route,
258
+ src: route.src.replace(new RegExp((0, escape_string_regexp_1.default)('(?:/)?$')), '(?:\\.rsc)(?:/)?$'),
259
+ dest: route.dest?.replace(/($|\?)/, '.rsc$1'),
260
+ });
263
261
  routes.push(route);
264
262
  continue;
265
263
  }
@@ -1249,6 +1247,9 @@ const onPrerenderRoute = (prerenderRouteArgs) => (routeKey, { isBlocking, isFall
1249
1247
  ? dataRoute
1250
1248
  : routeFileNoExt + '.json'}`),
1251
1249
  });
1250
+ if (isOmittedOrNotFound) {
1251
+ initialStatus = 404;
1252
+ }
1252
1253
  if (isAppPathRoute) {
1253
1254
  // for literal index routes we need to append an additional /index
1254
1255
  // due to the proxy's normalizing for /index routes
@@ -1500,7 +1501,7 @@ async function getStaticFiles(entryPath, entryDirectory, outputDirectory) {
1500
1501
  }
1501
1502
  exports.getStaticFiles = getStaticFiles;
1502
1503
  function normalizeIndexOutput(outputName, isServerMode) {
1503
- if (outputName !== '/index' && isServerMode) {
1504
+ if (outputName !== 'index' && outputName !== '/index' && isServerMode) {
1504
1505
  return outputName.replace(/\/index$/, '');
1505
1506
  }
1506
1507
  return outputName;
@@ -1594,6 +1595,21 @@ function normalizeRegions(regions) {
1594
1595
  }
1595
1596
  return newRegions;
1596
1597
  }
1598
+ function normalizeEdgeFunctionPath(shortPath, appPathRoutesManifest) {
1599
+ if (shortPath.startsWith('app/') &&
1600
+ (shortPath.endsWith('/page') ||
1601
+ shortPath.endsWith('/route') ||
1602
+ shortPath === 'app/_not-found')) {
1603
+ const ogRoute = shortPath.replace(/^app\//, '/');
1604
+ shortPath = (appPathRoutesManifest[ogRoute] ||
1605
+ shortPath.replace(/(^|\/)(page|route)$/, '')).replace(/^\//, '');
1606
+ if (!shortPath || shortPath === '/') {
1607
+ shortPath = 'index';
1608
+ }
1609
+ }
1610
+ return shortPath;
1611
+ }
1612
+ exports.normalizeEdgeFunctionPath = normalizeEdgeFunctionPath;
1597
1613
  async function getMiddlewareBundle({ entryPath, outputDirectory, routesManifest, isCorrectMiddlewareOrder, prerenderBypassToken, nextVersion, appPathRoutesManifest, }) {
1598
1614
  const middlewareManifest = await getMiddlewareManifest(entryPath, outputDirectory);
1599
1615
  const sortedFunctions = [
@@ -1710,21 +1726,11 @@ async function getMiddlewareBundle({ entryPath, outputDirectory, routesManifest,
1710
1726
  if (shortPath.startsWith('pages/')) {
1711
1727
  shortPath = shortPath.replace(/^pages\//, '');
1712
1728
  }
1713
- else if (shortPath.startsWith('app/') &&
1714
- (shortPath.endsWith('/page') ||
1715
- shortPath.endsWith('/route') ||
1716
- shortPath === 'app/_not-found')) {
1717
- const ogRoute = shortPath.replace(/^app\//, '/');
1718
- shortPath = (appPathRoutesManifest[ogRoute] ||
1719
- shortPath.replace(/(^|\/)(page|route)$/, '')).replace(/^\//, '');
1720
- if (!shortPath || shortPath === '/') {
1721
- shortPath = 'index';
1722
- }
1729
+ else {
1730
+ shortPath = normalizeEdgeFunctionPath(shortPath, appPathRoutesManifest);
1723
1731
  }
1724
1732
  if (routesManifest?.basePath) {
1725
- shortPath = path_1.default.posix
1726
- .join(routesManifest.basePath, shortPath)
1727
- .replace(/^\//, '');
1733
+ shortPath = normalizeIndexOutput(path_1.default.posix.join('./', routesManifest?.basePath, shortPath.replace(/^\//, '')), true);
1728
1734
  }
1729
1735
  worker.edgeFunction.name = shortPath;
1730
1736
  source.edgeFunctions[shortPath] = worker.edgeFunction;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/next",
3
- "version": "4.0.0",
3
+ "version": "4.0.2",
4
4
  "license": "Apache-2.0",
5
5
  "main": "./dist/index",
6
6
  "homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
@@ -26,7 +26,7 @@
26
26
  "@types/semver": "6.0.0",
27
27
  "@types/text-table": "0.2.1",
28
28
  "@types/webpack-sources": "3.2.0",
29
- "@vercel/build-utils": "7.0.0",
29
+ "@vercel/build-utils": "7.1.1",
30
30
  "@vercel/nft": "0.22.5",
31
31
  "@vercel/routing-utils": "3.0.0",
32
32
  "async-sema": "3.0.1",
@@ -45,7 +45,7 @@
45
45
  "ndjson": "2.0.0",
46
46
  "pretty-bytes": "5.3.0",
47
47
  "resolve-from": "5.0.0",
48
- "semver": "6.1.1",
48
+ "semver": "6.3.1",
49
49
  "set-cookie-parser": "2.4.6",
50
50
  "source-map": "0.7.3",
51
51
  "test-listen": "1.1.0",