@vercel/next 4.0.1 → 4.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -39,14 +39,21 @@ 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
42
  let appRscPrefetches = {};
44
43
  let appBuildTraces = {};
45
44
  let appDir = null;
46
45
  if (appPathRoutesManifest) {
47
46
  appDir = path_1.default.join(pagesDir, '../app');
48
47
  appBuildTraces = await (0, build_utils_1.glob)('**/*.js.nft.json', appDir);
49
- appRscPrefetches = await (0, build_utils_1.glob)(`**/*${APP_PREFETCH_SUFFIX}`, appDir);
48
+ appRscPrefetches = await (0, build_utils_1.glob)(`**/*${utils_1.RSC_PREFETCH_SUFFIX}`, appDir);
49
+ const rscContentTypeHeader = routesManifest?.rsc?.contentTypeHeader || utils_1.RSC_CONTENT_TYPE;
50
+ // ensure all appRscPrefetches have a contentType since this is used by Next.js
51
+ // to determine if it's a valid response
52
+ for (const value of Object.values(appRscPrefetches)) {
53
+ if (!value.contentType) {
54
+ value.contentType = rscContentTypeHeader;
55
+ }
56
+ }
50
57
  }
51
58
  const isCorrectNotFoundRoutes = semver_1.default.gte(nextVersion, CORRECT_NOT_FOUND_ROUTES_VERSION);
52
59
  const isCorrectMiddlewareOrder = semver_1.default.gte(nextVersion, CORRECT_MIDDLEWARE_ORDER_VERSION);
@@ -206,10 +213,17 @@ async function serverBuild({ dynamicPages, pagesDir, config = {}, functionsConfi
206
213
  // for notFound GS(S)P support
207
214
  if (i18n) {
208
215
  for (const locale of i18n.locales) {
209
- const static404File = staticPages[path_1.default.posix.join(entryDirectory, locale, '/404')] ||
210
- new build_utils_1.FileFsRef({
216
+ let static404File = staticPages[path_1.default.posix.join(entryDirectory, locale, '/404')];
217
+ if (!static404File) {
218
+ static404File = new build_utils_1.FileFsRef({
211
219
  fsPath: path_1.default.join(pagesDir, locale, '/404.html'),
212
220
  });
221
+ if (!fs_extra_1.default.existsSync(static404File.fsPath)) {
222
+ static404File = new build_utils_1.FileFsRef({
223
+ fsPath: path_1.default.join(pagesDir, '/404.html'),
224
+ });
225
+ }
226
+ }
213
227
  requiredFiles[path_1.default.relative(baseDir, static404File.fsPath)] =
214
228
  static404File;
215
229
  }
@@ -622,7 +636,25 @@ async function serverBuild({ dynamicPages, pagesDir, config = {}, functionsConfi
622
636
  });
623
637
  const isNextDataServerResolving = middleware.staticRoutes.length > 0 &&
624
638
  semver_1.default.gte(nextVersion, NEXT_DATA_MIDDLEWARE_RESOLVING_VERSION);
625
- 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));
639
+ 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));
640
+ const pagesPlaceholderRscEntries = {};
641
+ if (appDir) {
642
+ // since we attempt to rewrite all paths to an .rsc variant,
643
+ // we need to create dummy rsc outputs for all pages entries
644
+ // this is so that an RSC request to a `pages` entry will match
645
+ // rather than falling back to a catchall `app` entry
646
+ // on the nextjs side, invalid RSC response payloads will correctly trigger an mpa navigation
647
+ const pagesManifest = path_1.default.join(entryPath, outputDirectory, `server/pages-manifest.json`);
648
+ const pagesData = await fs_extra_1.default.readJSON(pagesManifest);
649
+ const pagesEntries = Object.keys(pagesData);
650
+ for (const page of pagesEntries) {
651
+ const pathName = page.startsWith('/') ? page.slice(1) : page;
652
+ pagesPlaceholderRscEntries[`${pathName}.rsc`] = new build_utils_1.FileBlob({
653
+ data: '{}',
654
+ contentType: 'application/json',
655
+ });
656
+ }
657
+ }
626
658
  const { staticFiles, publicDirectoryFiles, staticDirectoryFiles } = await (0, utils_1.getStaticFiles)(entryPath, entryDirectory, outputDirectory);
627
659
  const normalizeNextDataRoute = (isOverride = false) => {
628
660
  return isNextDataServerResolving
@@ -708,7 +740,7 @@ async function serverBuild({ dynamicPages, pagesDir, config = {}, functionsConfi
708
740
  if (ogRoute.endsWith('/route')) {
709
741
  continue;
710
742
  }
711
- route = path_1.default.posix.join('./', entryDirectory, route === '/' ? '/index' : route);
743
+ route = (0, utils_1.normalizeIndexOutput)(path_1.default.posix.join('./', entryDirectory, route === '/' ? '/index' : route), true);
712
744
  if (lambdas[route]) {
713
745
  lambdas[`${route}.rsc`] = lambdas[route];
714
746
  }
@@ -729,6 +761,7 @@ async function serverBuild({ dynamicPages, pagesDir, config = {}, functionsConfi
729
761
  ...publicDirectoryFiles,
730
762
  ...lambdas,
731
763
  ...appRscPrefetches,
764
+ ...pagesPlaceholderRscEntries,
732
765
  // Prerenders may override Lambdas -- this is an intentional behavior.
733
766
  ...prerenders,
734
767
  ...staticPages,
@@ -920,7 +953,7 @@ async function serverBuild({ dynamicPages, pagesDir, config = {}, functionsConfi
920
953
  key: rscPrefetchHeader,
921
954
  },
922
955
  ],
923
- dest: path_1.default.posix.join('/', entryDirectory, '/index.prefetch.rsc'),
956
+ dest: path_1.default.posix.join('/', entryDirectory, `/index${utils_1.RSC_PREFETCH_SUFFIX}`),
924
957
  headers: { vary: rscVaryHeader },
925
958
  continue: true,
926
959
  override: true,
@@ -933,7 +966,7 @@ async function serverBuild({ dynamicPages, pagesDir, config = {}, functionsConfi
933
966
  key: rscPrefetchHeader,
934
967
  },
935
968
  ],
936
- dest: path_1.default.posix.join('/', entryDirectory, `/$1${APP_PREFETCH_SUFFIX}`),
969
+ dest: path_1.default.posix.join('/', entryDirectory, `/$1${utils_1.RSC_PREFETCH_SUFFIX}`),
937
970
  headers: { vary: rscVaryHeader },
938
971
  continue: true,
939
972
  override: true,
@@ -998,7 +1031,7 @@ async function serverBuild({ dynamicPages, pagesDir, config = {}, functionsConfi
998
1031
  ...(rscPrefetchHeader
999
1032
  ? [
1000
1033
  {
1001
- src: path_1.default.posix.join('/', entryDirectory, `/index${APP_PREFETCH_SUFFIX}`),
1034
+ src: path_1.default.posix.join('/', entryDirectory, `/index${utils_1.RSC_PREFETCH_SUFFIX}`),
1002
1035
  dest: path_1.default.posix.join('/', entryDirectory, '/index.rsc'),
1003
1036
  has: [
1004
1037
  {
@@ -1010,7 +1043,7 @@ async function serverBuild({ dynamicPages, pagesDir, config = {}, functionsConfi
1010
1043
  override: true,
1011
1044
  },
1012
1045
  {
1013
- src: `^${path_1.default.posix.join('/', entryDirectory, `/(.+?)${APP_PREFETCH_SUFFIX}(?:/)?$`)}`,
1046
+ src: `^${path_1.default.posix.join('/', entryDirectory, `/(.+?)${utils_1.RSC_PREFETCH_SUFFIX}(?:/)?$`)}`,
1014
1047
  dest: path_1.default.posix.join('/', entryDirectory, '/$1.rsc'),
1015
1048
  has: [
1016
1049
  {
@@ -1023,62 +1056,17 @@ async function serverBuild({ dynamicPages, pagesDir, config = {}, functionsConfi
1023
1056
  },
1024
1057
  ]
1025
1058
  : []),
1026
- ...(appDir
1027
- ? [
1028
- // check routes that end in `.rsc` to see if a page with the resulting name (sans-.rsc) exists in the filesystem
1029
- // if so, we want to match that page instead. (This matters when prefetching a pages route while on an appdir route)
1030
- {
1031
- src: `^${path_1.default.posix.join('/', entryDirectory, '/(.*)\\.rsc$')}`,
1032
- dest: path_1.default.posix.join('/', entryDirectory, '/$1'),
1033
- has: [
1034
- {
1035
- type: 'header',
1036
- key: rscHeader,
1037
- },
1038
- ],
1039
- ...(rscPrefetchHeader
1040
- ? {
1041
- missing: [
1042
- {
1043
- type: 'header',
1044
- key: rscPrefetchHeader,
1045
- },
1046
- ],
1047
- }
1048
- : {}),
1049
- check: true,
1050
- },
1051
- ]
1052
- : []),
1053
1059
  // These need to come before handle: miss or else they are grouped
1054
1060
  // with that routing section
1055
1061
  ...afterFilesRewrites,
1056
- ...(appDir
1057
- ? [
1058
- // rewrite route back to `.rsc`, but skip checking fs
1059
- {
1060
- src: `^${path_1.default.posix.join('/', entryDirectory, '/((?!.+\\.rsc).+?)(?:/)?$')}`,
1061
- has: [
1062
- {
1063
- type: 'header',
1064
- key: rscHeader,
1065
- },
1066
- ],
1067
- dest: path_1.default.posix.join('/', entryDirectory, '/$1.rsc'),
1068
- headers: { vary: rscVaryHeader },
1069
- continue: true,
1070
- override: true,
1071
- },
1072
- ]
1073
- : []),
1074
- // make sure 404 page is used when a directory is matched without
1075
- // an index page
1076
1062
  { handle: 'resource' },
1077
1063
  ...fallbackRewrites,
1064
+ // make sure 404 page is used when a directory is matched without
1065
+ // an index page
1078
1066
  { src: path_1.default.posix.join('/', entryDirectory, '.*'), status: 404 },
1067
+ { handle: 'miss' },
1079
1068
  // We need to make sure to 404 for /_next after handle: miss since
1080
1069
  // handle: miss is called before rewrites and to prevent rewriting /_next
1081
- { handle: 'miss' },
1082
1070
  {
1083
1071
  src: path_1.default.posix.join('/', entryDirectory, '_next/static/(?:[^/]+/pages|pages|chunks|runtime|css|image|media)/.+'),
1084
1072
  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.RSC_PREFETCH_SUFFIX = exports.RSC_CONTENT_TYPE = 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"));
@@ -46,6 +46,8 @@ exports.KIB = 1024;
46
46
  exports.MIB = 1024 * exports.KIB;
47
47
  const prettyBytes = (n) => (0, bytes_1.default)(n, { unitSeparator: ' ' });
48
48
  exports.prettyBytes = prettyBytes;
49
+ exports.RSC_CONTENT_TYPE = 'x-component';
50
+ exports.RSC_PREFETCH_SUFFIX = '.prefetch.rsc';
49
51
  // Identify /[param]/ in route string
50
52
  // eslint-disable-next-line no-useless-escape
51
53
  const TEST_DYNAMIC_ROUTE = /\/\[[^\/]+?\](?=\/|$)/;
@@ -194,7 +196,7 @@ async function getRoutesManifest(entryPath, outputDirectory, nextVersion) {
194
196
  return routesManifest;
195
197
  }
196
198
  exports.getRoutesManifest = getRoutesManifest;
197
- async function getDynamicRoutes(entryPath, entryDirectory, dynamicPages, isDev, routesManifest, omittedRoutes, canUsePreviewMode, bypassToken, isServerMode, dynamicMiddlewareRouteMap, appPathRoutesManifest) {
199
+ async function getDynamicRoutes(entryPath, entryDirectory, dynamicPages, isDev, routesManifest, omittedRoutes, canUsePreviewMode, bypassToken, isServerMode, dynamicMiddlewareRouteMap) {
198
200
  if (routesManifest) {
199
201
  switch (routesManifest.version) {
200
202
  case 1:
@@ -253,13 +255,11 @@ async function getDynamicRoutes(entryPath, entryDirectory, dynamicPages, isDev,
253
255
  },
254
256
  ];
255
257
  }
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
- }
258
+ routes.push({
259
+ ...route,
260
+ src: route.src.replace(new RegExp((0, escape_string_regexp_1.default)('(?:/)?$')), '(?:\\.rsc)(?:/)?$'),
261
+ dest: route.dest?.replace(/($|\?)/, '.rsc$1'),
262
+ });
263
263
  routes.push(route);
264
264
  continue;
265
265
  }
@@ -1363,7 +1363,7 @@ const onPrerenderRoute = (prerenderRouteArgs) => (routeKey, { isBlocking, isFall
1363
1363
  const rscEnabled = !!routesManifest?.rsc;
1364
1364
  const rscVaryHeader = routesManifest?.rsc?.varyHeader ||
1365
1365
  'RSC, Next-Router-State-Tree, Next-Router-Prefetch';
1366
- const rscContentTypeHeader = routesManifest?.rsc?.contentTypeHeader || 'text/x-component';
1366
+ const rscContentTypeHeader = routesManifest?.rsc?.contentTypeHeader || exports.RSC_CONTENT_TYPE;
1367
1367
  let sourcePath;
1368
1368
  if (`/${outputPathPage}` !== srcRoute && srcRoute) {
1369
1369
  sourcePath = srcRoute;
@@ -1503,7 +1503,7 @@ async function getStaticFiles(entryPath, entryDirectory, outputDirectory) {
1503
1503
  }
1504
1504
  exports.getStaticFiles = getStaticFiles;
1505
1505
  function normalizeIndexOutput(outputName, isServerMode) {
1506
- if (outputName !== '/index' && isServerMode) {
1506
+ if (outputName !== 'index' && outputName !== '/index' && isServerMode) {
1507
1507
  return outputName.replace(/\/index$/, '');
1508
1508
  }
1509
1509
  return outputName;
@@ -1597,6 +1597,21 @@ function normalizeRegions(regions) {
1597
1597
  }
1598
1598
  return newRegions;
1599
1599
  }
1600
+ function normalizeEdgeFunctionPath(shortPath, appPathRoutesManifest) {
1601
+ if (shortPath.startsWith('app/') &&
1602
+ (shortPath.endsWith('/page') ||
1603
+ shortPath.endsWith('/route') ||
1604
+ shortPath === 'app/_not-found')) {
1605
+ const ogRoute = shortPath.replace(/^app\//, '/');
1606
+ shortPath = (appPathRoutesManifest[ogRoute] ||
1607
+ shortPath.replace(/(^|\/)(page|route)$/, '')).replace(/^\//, '');
1608
+ if (!shortPath || shortPath === '/') {
1609
+ shortPath = 'index';
1610
+ }
1611
+ }
1612
+ return shortPath;
1613
+ }
1614
+ exports.normalizeEdgeFunctionPath = normalizeEdgeFunctionPath;
1600
1615
  async function getMiddlewareBundle({ entryPath, outputDirectory, routesManifest, isCorrectMiddlewareOrder, prerenderBypassToken, nextVersion, appPathRoutesManifest, }) {
1601
1616
  const middlewareManifest = await getMiddlewareManifest(entryPath, outputDirectory);
1602
1617
  const sortedFunctions = [
@@ -1713,21 +1728,11 @@ async function getMiddlewareBundle({ entryPath, outputDirectory, routesManifest,
1713
1728
  if (shortPath.startsWith('pages/')) {
1714
1729
  shortPath = shortPath.replace(/^pages\//, '');
1715
1730
  }
1716
- else if (shortPath.startsWith('app/') &&
1717
- (shortPath.endsWith('/page') ||
1718
- shortPath.endsWith('/route') ||
1719
- shortPath === 'app/_not-found')) {
1720
- const ogRoute = shortPath.replace(/^app\//, '/');
1721
- shortPath = (appPathRoutesManifest[ogRoute] ||
1722
- shortPath.replace(/(^|\/)(page|route)$/, '')).replace(/^\//, '');
1723
- if (!shortPath || shortPath === '/') {
1724
- shortPath = 'index';
1725
- }
1731
+ else {
1732
+ shortPath = normalizeEdgeFunctionPath(shortPath, appPathRoutesManifest);
1726
1733
  }
1727
1734
  if (routesManifest?.basePath) {
1728
- shortPath = path_1.default.posix
1729
- .join(routesManifest.basePath, shortPath)
1730
- .replace(/^\//, '');
1735
+ shortPath = normalizeIndexOutput(path_1.default.posix.join('./', routesManifest?.basePath, shortPath.replace(/^\//, '')), true);
1731
1736
  }
1732
1737
  worker.edgeFunction.name = shortPath;
1733
1738
  source.edgeFunctions[shortPath] = worker.edgeFunction;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/next",
3
- "version": "4.0.1",
3
+ "version": "4.0.3",
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.2.0",
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",