@vercel/next 4.0.6 → 4.0.7

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/utils.js DELETED
@@ -1,1943 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
- Object.defineProperty(exports, "__esModule", { value: true });
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
- const build_utils_1 = require("@vercel/build-utils");
31
- const async_sema_1 = require("async-sema");
32
- const buffer_crc32_1 = __importDefault(require("buffer-crc32"));
33
- const fs_extra_1 = __importStar(require("fs-extra"));
34
- const path_1 = __importDefault(require("path"));
35
- const resolve_from_1 = __importDefault(require("resolve-from"));
36
- const semver_1 = __importDefault(require("semver"));
37
- const zlib_1 = __importDefault(require("zlib"));
38
- const url_1 = __importDefault(require("url"));
39
- const escape_string_regexp_1 = __importDefault(require("escape-string-regexp"));
40
- const _1 = require(".");
41
- const text_table_1 = __importDefault(require("text-table"));
42
- const get_edge_function_source_1 = require("./edge-function-source/get-edge-function-source");
43
- const sourcemapped_1 = require("./sourcemapped");
44
- const bytes_1 = __importDefault(require("bytes"));
45
- exports.KIB = 1024;
46
- exports.MIB = 1024 * exports.KIB;
47
- const prettyBytes = (n) => (0, bytes_1.default)(n, { unitSeparator: ' ' });
48
- exports.prettyBytes = prettyBytes;
49
- exports.RSC_CONTENT_TYPE = 'x-component';
50
- exports.RSC_PREFETCH_SUFFIX = '.prefetch.rsc';
51
- // Identify /[param]/ in route string
52
- // eslint-disable-next-line no-useless-escape
53
- const TEST_DYNAMIC_ROUTE = /\/\[[^\/]+?\](?=\/|$)/;
54
- function isDynamicRoute(route) {
55
- route = route.startsWith('/') ? route : `/${route}`;
56
- return TEST_DYNAMIC_ROUTE.test(route);
57
- }
58
- exports.isDynamicRoute = isDynamicRoute;
59
- /**
60
- * Validate if the entrypoint is allowed to be used
61
- */
62
- function validateEntrypoint(entrypoint) {
63
- if (!/package\.json$/.exec(entrypoint) &&
64
- !/next\.config\.js$/.exec(entrypoint)) {
65
- throw new build_utils_1.NowBuildError({
66
- message: 'Specified "src" for "@vercel/next" has to be "package.json" or "next.config.js"',
67
- code: 'NEXT_INCORRECT_SRC',
68
- });
69
- }
70
- }
71
- exports.validateEntrypoint = validateEntrypoint;
72
- /**
73
- * Exclude certain files from the files object
74
- */
75
- function excludeFiles(files, matcher) {
76
- return Object.keys(files).reduce((newFiles, filePath) => {
77
- if (matcher(filePath)) {
78
- return newFiles;
79
- }
80
- return {
81
- ...newFiles,
82
- [filePath]: files[filePath],
83
- };
84
- }, {});
85
- }
86
- exports.excludeFiles = excludeFiles;
87
- /**
88
- * Enforce specific package.json configuration for smallest possible lambda
89
- */
90
- function normalizePackageJson(defaultPackageJson = {}) {
91
- const dependencies = {};
92
- const devDependencies = {
93
- ...defaultPackageJson.dependencies,
94
- ...defaultPackageJson.devDependencies,
95
- };
96
- if (devDependencies.react) {
97
- dependencies.react = devDependencies.react;
98
- delete devDependencies.react;
99
- }
100
- if (devDependencies['react-dom']) {
101
- dependencies['react-dom'] = devDependencies['react-dom'];
102
- delete devDependencies['react-dom'];
103
- }
104
- delete devDependencies['next-server'];
105
- return {
106
- ...defaultPackageJson,
107
- dependencies: {
108
- // react and react-dom can be overwritten
109
- react: 'latest',
110
- 'react-dom': 'latest',
111
- ...dependencies,
112
- // next-server is forced to canary
113
- 'next-server': 'v7.0.2-canary.49',
114
- },
115
- devDependencies: {
116
- ...devDependencies,
117
- // next is forced to canary
118
- next: 'v7.0.2-canary.49',
119
- },
120
- scripts: {
121
- ...defaultPackageJson.scripts,
122
- 'now-build': 'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas',
123
- },
124
- };
125
- }
126
- exports.normalizePackageJson = normalizePackageJson;
127
- async function getNextConfig(workPath, entryPath) {
128
- const entryConfig = path_1.default.join(entryPath, './next.config.js');
129
- if (await fs_extra_1.default.pathExists(entryConfig)) {
130
- return fs_extra_1.default.readFile(entryConfig, 'utf8');
131
- }
132
- const workConfig = path_1.default.join(workPath, './next.config.js');
133
- if (await fs_extra_1.default.pathExists(workConfig)) {
134
- return fs_extra_1.default.readFile(workConfig, 'utf8');
135
- }
136
- return null;
137
- }
138
- exports.getNextConfig = getNextConfig;
139
- function getImagesConfig(imagesManifest) {
140
- return imagesManifest?.images?.loader === 'default' &&
141
- imagesManifest.images?.unoptimized !== true
142
- ? {
143
- domains: imagesManifest.images.domains,
144
- sizes: imagesManifest.images.sizes,
145
- remotePatterns: imagesManifest.images.remotePatterns,
146
- minimumCacheTTL: imagesManifest.images.minimumCacheTTL,
147
- formats: imagesManifest.images.formats,
148
- dangerouslyAllowSVG: imagesManifest.images.dangerouslyAllowSVG,
149
- contentSecurityPolicy: imagesManifest.images.contentSecurityPolicy,
150
- contentDispositionType: imagesManifest.images.contentDispositionType,
151
- }
152
- : undefined;
153
- }
154
- exports.getImagesConfig = getImagesConfig;
155
- function normalizePage(page) {
156
- // Resolve on anything that doesn't start with `/`
157
- if (!page.startsWith('/')) {
158
- page = `/${page}`;
159
- }
160
- // remove '/index' from the end
161
- page = page.replace(/\/index$/, '/');
162
- return page;
163
- }
164
- exports.normalizePage = normalizePage;
165
- async function getRoutesManifest(entryPath, outputDirectory, nextVersion) {
166
- const shouldHaveManifest = nextVersion && semver_1.default.gte(nextVersion, '9.1.4-canary.0');
167
- if (!shouldHaveManifest)
168
- return;
169
- const pathRoutesManifest = path_1.default.join(entryPath, outputDirectory, 'routes-manifest.json');
170
- const hasRoutesManifest = await fs_extra_1.default
171
- .access(pathRoutesManifest)
172
- .then(() => true)
173
- .catch(() => false);
174
- if (shouldHaveManifest && !hasRoutesManifest) {
175
- throw new build_utils_1.NowBuildError({
176
- message: `The file "${pathRoutesManifest}" couldn't be found. This is often caused by a misconfiguration in your project.`,
177
- link: 'https://err.sh/vercel/vercel/now-next-routes-manifest',
178
- code: 'NEXT_NO_ROUTES_MANIFEST',
179
- });
180
- }
181
- const routesManifest = await fs_extra_1.default.readJSON(pathRoutesManifest);
182
- // remove temporary array based routeKeys from v1/v2 of routes
183
- // manifest since it can result in invalid routes
184
- for (const route of routesManifest.dataRoutes || []) {
185
- if (Array.isArray(route.routeKeys)) {
186
- delete route.routeKeys;
187
- delete route.namedDataRouteRegex;
188
- }
189
- }
190
- for (const route of routesManifest.dynamicRoutes || []) {
191
- if ('routeKeys' in route && Array.isArray(route.routeKeys)) {
192
- delete route.routeKeys;
193
- delete route.namedRegex;
194
- }
195
- }
196
- return routesManifest;
197
- }
198
- exports.getRoutesManifest = getRoutesManifest;
199
- async function getDynamicRoutes(entryPath, entryDirectory, dynamicPages, isDev, routesManifest, omittedRoutes, canUsePreviewMode, bypassToken, isServerMode, dynamicMiddlewareRouteMap) {
200
- if (routesManifest) {
201
- switch (routesManifest.version) {
202
- case 1:
203
- case 2: {
204
- return routesManifest.dynamicRoutes
205
- .filter(({ page }) => canUsePreviewMode || !omittedRoutes?.has(page))
206
- .map(({ page, regex }) => {
207
- return {
208
- src: regex,
209
- dest: !isDev ? path_1.default.posix.join('/', entryDirectory, page) : page,
210
- check: true,
211
- status: canUsePreviewMode && omittedRoutes?.has(page) ? 404 : undefined,
212
- };
213
- });
214
- }
215
- case 3:
216
- case 4: {
217
- const routes = [];
218
- for (const dynamicRoute of routesManifest.dynamicRoutes) {
219
- if (!canUsePreviewMode && omittedRoutes?.has(dynamicRoute.page)) {
220
- continue;
221
- }
222
- const params = dynamicRoute;
223
- if ('isMiddleware' in params) {
224
- const route = dynamicMiddlewareRouteMap?.get(params.page);
225
- if (!route) {
226
- throw new Error(`Could not find dynamic middleware route for ${params.page}`);
227
- }
228
- routes.push(route);
229
- continue;
230
- }
231
- const { page, namedRegex, regex, routeKeys } = params;
232
- const route = {
233
- src: namedRegex || regex,
234
- dest: `${!isDev ? path_1.default.posix.join('/', entryDirectory, page) : page}${routeKeys
235
- ? `?${Object.keys(routeKeys)
236
- .map(key => `${routeKeys[key]}=$${key}`)
237
- .join('&')}`
238
- : ''}`,
239
- };
240
- if (!isServerMode) {
241
- route.check = true;
242
- }
243
- if (isServerMode && canUsePreviewMode && omittedRoutes?.has(page)) {
244
- // only match this route when in preview mode so
245
- // preview works for non-prerender fallback: false pages
246
- route.has = [
247
- {
248
- type: 'cookie',
249
- key: '__prerender_bypass',
250
- value: bypassToken || undefined,
251
- },
252
- {
253
- type: 'cookie',
254
- key: '__next_preview_data',
255
- },
256
- ];
257
- }
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
- routes.push(route);
264
- continue;
265
- }
266
- return routes;
267
- }
268
- default: {
269
- // update MIN_ROUTES_MANIFEST_VERSION
270
- throw new build_utils_1.NowBuildError({
271
- message: 'This version of `@vercel/next` does not support the version of Next.js you are trying to deploy.\n' +
272
- 'Please upgrade your `@vercel/next` builder and try again. Contact support if this continues to happen.',
273
- code: 'NEXT_VERSION_UPGRADE',
274
- });
275
- }
276
- }
277
- }
278
- // FALLBACK:
279
- // When `routes-manifest.json` does not exist (old Next.js versions), we'll try to
280
- // require the methods we need from Next.js' internals.
281
- if (!dynamicPages.length) {
282
- return [];
283
- }
284
- let getRouteRegex = undefined;
285
- let getSortedRoutes;
286
- try {
287
- // NOTE: `eval('require')` is necessary to avoid bad transpilation to `__webpack_require__`
288
- ({ getRouteRegex, getSortedRoutes } = eval('require')((0, resolve_from_1.default)(entryPath, 'next-server/dist/lib/router/utils')));
289
- if (typeof getRouteRegex !== 'function') {
290
- getRouteRegex = undefined;
291
- }
292
- }
293
- catch (_) { } // eslint-disable-line no-empty
294
- if (!getRouteRegex || !getSortedRoutes) {
295
- try {
296
- // NOTE: `eval('require')` is necessary to avoid bad transpilation to `__webpack_require__`
297
- ({ getRouteRegex, getSortedRoutes } = eval('require')((0, resolve_from_1.default)(entryPath, 'next/dist/next-server/lib/router/utils')));
298
- if (typeof getRouteRegex !== 'function') {
299
- getRouteRegex = undefined;
300
- }
301
- }
302
- catch (_) { } // eslint-disable-line no-empty
303
- }
304
- if (!getRouteRegex || !getSortedRoutes) {
305
- throw new build_utils_1.NowBuildError({
306
- message: 'Found usage of dynamic routes but not on a new enough version of Next.js.',
307
- code: 'NEXT_DYNAMIC_ROUTES_OUTDATED',
308
- });
309
- }
310
- const pageMatchers = getSortedRoutes(dynamicPages).map(pageName => ({
311
- pageName,
312
- matcher: getRouteRegex && getRouteRegex(pageName).re,
313
- }));
314
- const routes = [];
315
- pageMatchers.forEach(pageMatcher => {
316
- // in `vercel dev` we don't need to prefix the destination
317
- const dest = !isDev
318
- ? path_1.default.posix.join('/', entryDirectory, pageMatcher.pageName)
319
- : pageMatcher.pageName;
320
- if (pageMatcher && pageMatcher.matcher) {
321
- routes.push({
322
- src: pageMatcher.matcher.source,
323
- dest,
324
- check: !isDev,
325
- });
326
- }
327
- });
328
- return routes;
329
- }
330
- exports.getDynamicRoutes = getDynamicRoutes;
331
- function localizeDynamicRoutes(dynamicRoutes, dynamicPrefix, entryDirectory, staticPages, prerenderManifest, routesManifest, isServerMode, isCorrectLocaleAPIRoutes, inversedAppPathRoutesManifest) {
332
- return dynamicRoutes.map((route) => {
333
- // i18n is already handled for middleware
334
- if (route.middleware !== undefined || route.middlewarePath !== undefined)
335
- return route;
336
- const { i18n } = routesManifest || {};
337
- if (i18n) {
338
- const { pathname } = url_1.default.parse(route.dest);
339
- const pathnameNoPrefix = pathname?.replace(dynamicPrefix, '');
340
- const isFallback = prerenderManifest.fallbackRoutes[pathname];
341
- const isBlocking = prerenderManifest.blockingFallbackRoutes[pathname];
342
- const isApiRoute = pathnameNoPrefix === '/api' || pathnameNoPrefix?.startsWith('/api/');
343
- const isAutoExport = staticPages[addLocaleOrDefault(pathname, routesManifest).substring(1)];
344
- const isAppRoute = inversedAppPathRoutesManifest?.[pathnameNoPrefix || ''];
345
- const isLocalePrefixed = isFallback || isBlocking || isAutoExport || isServerMode;
346
- route.src = route.src.replace('^', `^${dynamicPrefix ? `${dynamicPrefix}[/]?` : '[/]?'}(?${isLocalePrefixed ? '<nextLocale>' : ':'}${i18n.locales.map(locale => (0, escape_string_regexp_1.default)(locale)).join('|')})?`);
347
- if (isLocalePrefixed &&
348
- !(isCorrectLocaleAPIRoutes && isApiRoute) &&
349
- !isAppRoute) {
350
- // ensure destination has locale prefix to match prerender output
351
- // path so that the prerender object is used
352
- route.dest = route.dest.replace(`${path_1.default.posix.join('/', entryDirectory, '/')}`, `${path_1.default.posix.join('/', entryDirectory, '$nextLocale', '/')}`);
353
- }
354
- }
355
- else {
356
- route.src = route.src.replace('^', `^${dynamicPrefix}`);
357
- }
358
- return route;
359
- });
360
- }
361
- exports.localizeDynamicRoutes = localizeDynamicRoutes;
362
- async function getImagesManifest(entryPath, outputDirectory) {
363
- const pathImagesManifest = path_1.default.join(entryPath, outputDirectory, 'images-manifest.json');
364
- const hasImagesManifest = await fs_extra_1.default
365
- .access(pathImagesManifest)
366
- .then(() => true)
367
- .catch(() => false);
368
- if (!hasImagesManifest) {
369
- return undefined;
370
- }
371
- return fs_extra_1.default.readJson(pathImagesManifest);
372
- }
373
- exports.getImagesManifest = getImagesManifest;
374
- function filterStaticPages(staticPageFiles, dynamicPages, entryDirectory, htmlContentType, prerenderManifest, routesManifest) {
375
- const staticPages = {};
376
- Object.keys(staticPageFiles).forEach((page) => {
377
- const pathname = page.replace(/\.html$/, '');
378
- const routeName = normalizeLocalePath(normalizePage(pathname), routesManifest?.i18n?.locales).pathname;
379
- // Prerendered routes emit a `.html` file but should not be treated as a
380
- // static page.
381
- // Lazily prerendered routes have a fallback `.html` file on newer
382
- // Next.js versions so we need to also not treat it as a static page here.
383
- if (prerenderManifest.staticRoutes[routeName] ||
384
- prerenderManifest.fallbackRoutes[routeName] ||
385
- prerenderManifest.staticRoutes[normalizePage(pathname)] ||
386
- prerenderManifest.fallbackRoutes[normalizePage(pathname)]) {
387
- return;
388
- }
389
- const staticRoute = path_1.default.posix.join(entryDirectory, pathname);
390
- staticPages[staticRoute] = staticPageFiles[page];
391
- staticPages[staticRoute].contentType = htmlContentType;
392
- if (isDynamicRoute(pathname)) {
393
- dynamicPages.push(routeName);
394
- return;
395
- }
396
- });
397
- return staticPages;
398
- }
399
- exports.filterStaticPages = filterStaticPages;
400
- function getFilesMapFromReasons(fileList, reasons, ignoreFn) {
401
- // this uses the reasons tree to collect files specific to a
402
- // certain parent allowing us to not have to trace each parent
403
- // separately
404
- const parentFilesMap = new Map();
405
- function propagateToParents(parents, file, seen = new Set()) {
406
- for (const parent of parents || []) {
407
- if (!seen.has(parent)) {
408
- seen.add(parent);
409
- let parentFiles = parentFilesMap.get(parent);
410
- if (!parentFiles) {
411
- parentFiles = new Set();
412
- parentFilesMap.set(parent, parentFiles);
413
- }
414
- if (!ignoreFn?.(file, parent)) {
415
- parentFiles.add(file);
416
- }
417
- const parentReason = reasons.get(parent);
418
- if (parentReason?.parents) {
419
- propagateToParents(parentReason.parents, file, seen);
420
- }
421
- }
422
- }
423
- }
424
- for (const file of fileList) {
425
- const reason = reasons.get(file);
426
- const isInitial = reason?.type.length === 1 && reason.type.includes('initial');
427
- if (!reason ||
428
- !reason.parents ||
429
- (isInitial && reason.parents.size === 0)) {
430
- continue;
431
- }
432
- propagateToParents(reason.parents, file);
433
- }
434
- return parentFilesMap;
435
- }
436
- exports.getFilesMapFromReasons = getFilesMapFromReasons;
437
- const collectTracedFiles = (baseDir, lstatResults, lstatSema, reasons, files) => async (file) => {
438
- const reason = reasons.get(file);
439
- if (reason && reason.type.includes('initial')) {
440
- // Initial files are manually added to the lambda later
441
- return;
442
- }
443
- const filePath = path_1.default.join(baseDir, file);
444
- if (!lstatResults[filePath]) {
445
- lstatResults[filePath] = lstatSema
446
- .acquire()
447
- .then(() => (0, fs_extra_1.lstat)(filePath))
448
- .finally(() => lstatSema.release());
449
- }
450
- const { mode } = await lstatResults[filePath];
451
- files[file] = new build_utils_1.FileFsRef({
452
- fsPath: path_1.default.join(baseDir, file),
453
- mode,
454
- });
455
- };
456
- exports.collectTracedFiles = collectTracedFiles;
457
- exports.ExperimentalTraceVersion = `9.0.4-canary.1`;
458
- const compressBuffer = (buf) => {
459
- return new Promise((resolve, reject) => {
460
- zlib_1.default.deflateRaw(buf, { level: zlib_1.default.constants.Z_BEST_COMPRESSION }, (err, compBuf) => {
461
- if (err)
462
- return reject(err);
463
- resolve(compBuf);
464
- });
465
- });
466
- };
467
- async function createPseudoLayer(files) {
468
- const pseudoLayer = {};
469
- let pseudoLayerBytes = 0;
470
- for (const fileName of Object.keys(files)) {
471
- const file = files[fileName];
472
- if ((0, build_utils_1.isSymbolicLink)(file.mode)) {
473
- const symlinkTarget = await fs_extra_1.default.readlink(file.fsPath);
474
- pseudoLayer[fileName] = {
475
- file,
476
- isSymlink: true,
477
- symlinkTarget,
478
- };
479
- }
480
- else {
481
- const origBuffer = await (0, build_utils_1.streamToBuffer)(file.toStream());
482
- const compBuffer = await compressBuffer(origBuffer);
483
- pseudoLayerBytes += compBuffer.byteLength;
484
- pseudoLayer[fileName] = {
485
- file,
486
- compBuffer,
487
- isSymlink: false,
488
- crc32: buffer_crc32_1.default.unsigned(origBuffer),
489
- uncompressedSize: origBuffer.byteLength,
490
- };
491
- }
492
- }
493
- return { pseudoLayer, pseudoLayerBytes };
494
- }
495
- exports.createPseudoLayer = createPseudoLayer;
496
- // measured with 1, 2, 5, 10, and `os.cpus().length || 5`
497
- // and sema(1) produced the best results
498
- const createLambdaSema = new async_sema_1.Sema(1);
499
- async function createLambdaFromPseudoLayers({ files: baseFiles, layers, isStreaming, nextVersion, ...lambdaOptions }) {
500
- await createLambdaSema.acquire();
501
- const files = {};
502
- const addedFiles = new Set();
503
- // Add files from pseudo layers
504
- for (const layer of layers) {
505
- for (const seedKey of Object.keys(layer)) {
506
- if (addedFiles.has(seedKey)) {
507
- // File was already added in a previous pseudo layer
508
- continue;
509
- }
510
- const item = layer[seedKey];
511
- files[seedKey] = item.file;
512
- addedFiles.add(seedKey);
513
- }
514
- }
515
- for (const fileName of Object.keys(baseFiles)) {
516
- if (addedFiles.has(fileName)) {
517
- // File was already added in a previous pseudo layer
518
- continue;
519
- }
520
- const file = baseFiles[fileName];
521
- files[fileName] = file;
522
- addedFiles.add(fileName);
523
- }
524
- createLambdaSema.release();
525
- return new build_utils_1.NodejsLambda({
526
- ...lambdaOptions,
527
- ...(isStreaming
528
- ? {
529
- supportsResponseStreaming: true,
530
- }
531
- : {}),
532
- files,
533
- shouldAddHelpers: false,
534
- shouldAddSourcemapSupport: false,
535
- supportsMultiPayloads: true,
536
- framework: {
537
- slug: 'nextjs',
538
- version: nextVersion,
539
- },
540
- });
541
- }
542
- exports.createLambdaFromPseudoLayers = createLambdaFromPseudoLayers;
543
- async function getExportIntent(entryPath) {
544
- const pathExportMarker = path_1.default.join(entryPath, '.next', 'export-marker.json');
545
- const hasExportMarker = await fs_extra_1.default
546
- .access(pathExportMarker, fs_extra_1.default.constants.F_OK)
547
- .then(() => true)
548
- .catch(() => false);
549
- if (!hasExportMarker) {
550
- return false;
551
- }
552
- const manifest = JSON.parse(await fs_extra_1.default.readFile(pathExportMarker, 'utf8'));
553
- switch (manifest.version) {
554
- case 1: {
555
- if (manifest.hasExportPathMap !== true) {
556
- return false;
557
- }
558
- return { trailingSlash: manifest.exportTrailingSlash };
559
- }
560
- default: {
561
- return false;
562
- }
563
- }
564
- }
565
- exports.getExportIntent = getExportIntent;
566
- async function getExportStatus(entryPath) {
567
- const pathExportDetail = path_1.default.join(entryPath, '.next', 'export-detail.json');
568
- const hasExportDetail = await fs_extra_1.default
569
- .access(pathExportDetail, fs_extra_1.default.constants.F_OK)
570
- .then(() => true)
571
- .catch(() => false);
572
- if (!hasExportDetail) {
573
- return false;
574
- }
575
- const manifest = JSON.parse(await fs_extra_1.default.readFile(pathExportDetail, 'utf8'));
576
- switch (manifest.version) {
577
- case 1: {
578
- return {
579
- success: !!manifest.success,
580
- outDirectory: manifest.outDirectory,
581
- };
582
- }
583
- default: {
584
- return false;
585
- }
586
- }
587
- }
588
- exports.getExportStatus = getExportStatus;
589
- async function getRequiredServerFilesManifest(entryPath, outputDirectory) {
590
- const pathRequiredServerFilesManifest = path_1.default.join(entryPath, outputDirectory, 'required-server-files.json');
591
- const hasManifest = await fs_extra_1.default
592
- .access(pathRequiredServerFilesManifest, fs_extra_1.default.constants.F_OK)
593
- .then(() => true)
594
- .catch(() => false);
595
- if (!hasManifest) {
596
- return false;
597
- }
598
- const manifestData = JSON.parse(await fs_extra_1.default.readFile(pathRequiredServerFilesManifest, 'utf8'));
599
- const requiredServerFiles = {
600
- files: [],
601
- ignore: [],
602
- config: {},
603
- appDir: manifestData.appDir,
604
- relativeAppDir: manifestData.relativeAppDir,
605
- };
606
- switch (manifestData.version) {
607
- case 1: {
608
- requiredServerFiles.files = manifestData.files;
609
- requiredServerFiles.ignore = manifestData.ignore;
610
- requiredServerFiles.config = manifestData.config;
611
- requiredServerFiles.appDir = manifestData.appDir;
612
- break;
613
- }
614
- default: {
615
- throw new Error(`Invalid required-server-files manifest version ${manifestData.version}, please contact support if this error persists`);
616
- }
617
- }
618
- return requiredServerFiles;
619
- }
620
- exports.getRequiredServerFilesManifest = getRequiredServerFilesManifest;
621
- async function getPrerenderManifest(entryPath, outputDirectory) {
622
- const pathPrerenderManifest = path_1.default.join(entryPath, outputDirectory, 'prerender-manifest.json');
623
- const hasManifest = await fs_extra_1.default
624
- .access(pathPrerenderManifest, fs_extra_1.default.constants.F_OK)
625
- .then(() => true)
626
- .catch(() => false);
627
- if (!hasManifest) {
628
- return {
629
- staticRoutes: {},
630
- blockingFallbackRoutes: {},
631
- fallbackRoutes: {},
632
- bypassToken: null,
633
- omittedRoutes: {},
634
- notFoundRoutes: [],
635
- isLocalePrefixed: false,
636
- };
637
- }
638
- const manifest = JSON.parse(await fs_extra_1.default.readFile(pathPrerenderManifest, 'utf8'));
639
- switch (manifest.version) {
640
- case 1: {
641
- const routes = Object.keys(manifest.routes);
642
- const lazyRoutes = Object.keys(manifest.dynamicRoutes);
643
- const ret = {
644
- staticRoutes: {},
645
- blockingFallbackRoutes: {},
646
- fallbackRoutes: {},
647
- bypassToken: (manifest.preview && manifest.preview.previewModeId) || null,
648
- omittedRoutes: {},
649
- notFoundRoutes: [],
650
- isLocalePrefixed: false,
651
- };
652
- routes.forEach(route => {
653
- const { initialRevalidateSeconds, dataRoute, srcRoute } = manifest.routes[route];
654
- ret.staticRoutes[route] = {
655
- initialRevalidate: initialRevalidateSeconds === false
656
- ? false
657
- : Math.max(1, initialRevalidateSeconds),
658
- dataRoute,
659
- srcRoute,
660
- };
661
- });
662
- lazyRoutes.forEach(lazyRoute => {
663
- const { routeRegex, fallback, dataRoute, dataRouteRegex } = manifest.dynamicRoutes[lazyRoute];
664
- if (fallback) {
665
- ret.fallbackRoutes[lazyRoute] = {
666
- routeRegex,
667
- fallback,
668
- dataRoute,
669
- dataRouteRegex,
670
- };
671
- }
672
- else {
673
- ret.blockingFallbackRoutes[lazyRoute] = {
674
- routeRegex,
675
- dataRoute,
676
- dataRouteRegex,
677
- };
678
- }
679
- });
680
- return ret;
681
- }
682
- case 2:
683
- case 3:
684
- case 4: {
685
- const routes = Object.keys(manifest.routes);
686
- const lazyRoutes = Object.keys(manifest.dynamicRoutes);
687
- const ret = {
688
- staticRoutes: {},
689
- blockingFallbackRoutes: {},
690
- fallbackRoutes: {},
691
- bypassToken: manifest.preview.previewModeId,
692
- omittedRoutes: {},
693
- notFoundRoutes: [],
694
- isLocalePrefixed: manifest.version > 2,
695
- };
696
- if (manifest.notFoundRoutes) {
697
- ret.notFoundRoutes.push(...manifest.notFoundRoutes);
698
- }
699
- routes.forEach(route => {
700
- const { initialRevalidateSeconds, dataRoute, srcRoute } = manifest.routes[route];
701
- let initialStatus;
702
- let initialHeaders;
703
- let experimentalBypassFor;
704
- if (manifest.version === 4) {
705
- initialStatus = manifest.routes[route].initialStatus;
706
- initialHeaders = manifest.routes[route].initialHeaders;
707
- experimentalBypassFor = manifest.routes[route].experimentalBypassFor;
708
- }
709
- ret.staticRoutes[route] = {
710
- initialRevalidate: initialRevalidateSeconds === false
711
- ? false
712
- : Math.max(1, initialRevalidateSeconds),
713
- dataRoute,
714
- srcRoute,
715
- initialStatus,
716
- initialHeaders,
717
- experimentalBypassFor,
718
- };
719
- });
720
- lazyRoutes.forEach(lazyRoute => {
721
- const { routeRegex, fallback, dataRoute, dataRouteRegex } = manifest.dynamicRoutes[lazyRoute];
722
- let experimentalBypassFor;
723
- if (manifest.version === 4) {
724
- experimentalBypassFor =
725
- manifest.dynamicRoutes[lazyRoute].experimentalBypassFor;
726
- }
727
- if (typeof fallback === 'string') {
728
- ret.fallbackRoutes[lazyRoute] = {
729
- experimentalBypassFor,
730
- routeRegex,
731
- fallback,
732
- dataRoute,
733
- dataRouteRegex,
734
- };
735
- }
736
- else if (fallback === null) {
737
- ret.blockingFallbackRoutes[lazyRoute] = {
738
- experimentalBypassFor,
739
- routeRegex,
740
- dataRoute,
741
- dataRouteRegex,
742
- };
743
- }
744
- else {
745
- // Fallback behavior is disabled, all routes would've been provided
746
- // in the top-level `routes` key (`staticRoutes`).
747
- ret.omittedRoutes[lazyRoute] = {
748
- experimentalBypassFor,
749
- routeRegex,
750
- dataRoute,
751
- dataRouteRegex,
752
- };
753
- }
754
- });
755
- return ret;
756
- }
757
- default: {
758
- return {
759
- staticRoutes: {},
760
- blockingFallbackRoutes: {},
761
- fallbackRoutes: {},
762
- bypassToken: null,
763
- omittedRoutes: {},
764
- notFoundRoutes: [],
765
- isLocalePrefixed: false,
766
- };
767
- }
768
- }
769
- }
770
- exports.getPrerenderManifest = getPrerenderManifest;
771
- // We only need this once per build
772
- let _usesSrcCache;
773
- async function usesSrcDirectory(workPath) {
774
- if (!_usesSrcCache) {
775
- const sourcePages = path_1.default.join(workPath, 'src', 'pages');
776
- try {
777
- if ((await fs_extra_1.default.stat(sourcePages)).isDirectory()) {
778
- _usesSrcCache = true;
779
- }
780
- }
781
- catch (_err) {
782
- _usesSrcCache = false;
783
- }
784
- }
785
- if (!_usesSrcCache) {
786
- const sourceAppdir = path_1.default.join(workPath, 'src', 'app');
787
- try {
788
- if ((await fs_extra_1.default.stat(sourceAppdir)).isDirectory()) {
789
- _usesSrcCache = true;
790
- }
791
- }
792
- catch (_err) {
793
- _usesSrcCache = false;
794
- }
795
- }
796
- return Boolean(_usesSrcCache);
797
- }
798
- async function getSourceFilePathFromPage({ workPath, page, pageExtensions, }) {
799
- const usesSrcDir = await usesSrcDirectory(workPath);
800
- const extensionsToTry = pageExtensions || ['js', 'jsx', 'ts', 'tsx'];
801
- for (const pageType of ['pages', 'app']) {
802
- let fsPath = path_1.default.join(workPath, pageType, page);
803
- if (usesSrcDir) {
804
- fsPath = path_1.default.join(workPath, 'src', pageType, page);
805
- }
806
- if (fs_extra_1.default.existsSync(fsPath)) {
807
- return path_1.default.relative(workPath, fsPath);
808
- }
809
- const extensionless = fsPath.replace(path_1.default.extname(fsPath), '');
810
- for (const ext of extensionsToTry) {
811
- fsPath = `${extensionless}.${ext}`;
812
- // for appDir, we need to treat "index.js" as root-level "page.js"
813
- if (pageType === 'app' &&
814
- extensionless ===
815
- path_1.default.join(workPath, `${usesSrcDir ? 'src/' : ''}app/index`)) {
816
- fsPath = `${extensionless.replace(/index$/, 'page')}.${ext}`;
817
- }
818
- if (fs_extra_1.default.existsSync(fsPath)) {
819
- return path_1.default.relative(workPath, fsPath);
820
- }
821
- }
822
- if (isDirectory(extensionless)) {
823
- if (pageType === 'pages') {
824
- for (const ext of extensionsToTry) {
825
- fsPath = path_1.default.join(extensionless, `index.${ext}`);
826
- if (fs_extra_1.default.existsSync(fsPath)) {
827
- return path_1.default.relative(workPath, fsPath);
828
- }
829
- }
830
- // appDir
831
- }
832
- else {
833
- for (const ext of extensionsToTry) {
834
- // RSC
835
- fsPath = path_1.default.join(extensionless, `page.${ext}`);
836
- if (fs_extra_1.default.existsSync(fsPath)) {
837
- return path_1.default.relative(workPath, fsPath);
838
- }
839
- // Route Handlers
840
- fsPath = path_1.default.join(extensionless, `route.${ext}`);
841
- if (fs_extra_1.default.existsSync(fsPath)) {
842
- return path_1.default.relative(workPath, fsPath);
843
- }
844
- }
845
- }
846
- }
847
- }
848
- console.log(`WARNING: Unable to find source file for page ${page} with extensions: ${extensionsToTry.join(', ')}, this can cause functions config from \`vercel.json\` to not be applied`);
849
- return '';
850
- }
851
- exports.getSourceFilePathFromPage = getSourceFilePathFromPage;
852
- function isDirectory(path) {
853
- return fs_extra_1.default.existsSync(path) && fs_extra_1.default.lstatSync(path).isDirectory();
854
- }
855
- function normalizeLocalePath(pathname, locales) {
856
- let detectedLocale;
857
- // first item will be empty string from splitting at first char
858
- const pathnameParts = pathname.split('/');
859
- (locales || []).some(locale => {
860
- if (pathnameParts[1].toLowerCase() === locale.toLowerCase()) {
861
- detectedLocale = locale;
862
- pathnameParts.splice(1, 1);
863
- pathname = pathnameParts.join('/') || '/';
864
- return true;
865
- }
866
- return false;
867
- });
868
- return {
869
- pathname,
870
- detectedLocale,
871
- };
872
- }
873
- exports.normalizeLocalePath = normalizeLocalePath;
874
- function addLocaleOrDefault(pathname, routesManifest, locale) {
875
- if (!routesManifest?.i18n)
876
- return pathname;
877
- if (!locale)
878
- locale = routesManifest.i18n.defaultLocale;
879
- return locale
880
- ? `/${locale}${pathname === '/index' ? '' : pathname}`
881
- : pathname;
882
- }
883
- exports.addLocaleOrDefault = addLocaleOrDefault;
884
- exports.MAX_UNCOMPRESSED_LAMBDA_SIZE = 250 * exports.MIB;
885
- const LAMBDA_RESERVED_UNCOMPRESSED_SIZE = 2.5 * exports.MIB;
886
- const LAMBDA_RESERVED_COMPRESSED_SIZE = 250 * exports.KIB;
887
- async function getPageLambdaGroups({ entryPath, config, functionsConfigManifest, pages, prerenderRoutes, pageTraces, compressedPages, tracedPseudoLayer, initialPseudoLayer, initialPseudoLayerUncompressed, lambdaCompressedByteLimit, internalPages, pageExtensions, }) {
888
- const groups = [];
889
- for (const page of pages) {
890
- const newPages = [...internalPages, page];
891
- const routeName = normalizePage(page.replace(/\.js$/, ''));
892
- const isPrerenderRoute = prerenderRoutes.has(routeName);
893
- let opts = {};
894
- if (functionsConfigManifest &&
895
- functionsConfigManifest.functions[routeName]) {
896
- opts = functionsConfigManifest.functions[routeName];
897
- }
898
- if (config && config.functions) {
899
- const sourceFile = await getSourceFilePathFromPage({
900
- workPath: entryPath,
901
- page,
902
- pageExtensions,
903
- });
904
- const vercelConfigOpts = await (0, build_utils_1.getLambdaOptionsFromFunction)({
905
- sourceFile,
906
- config,
907
- });
908
- opts = { ...vercelConfigOpts, ...opts };
909
- }
910
- let matchingGroup = groups.find(group => {
911
- const matches = group.maxDuration === opts.maxDuration &&
912
- group.memory === opts.memory &&
913
- group.isPrerenders === isPrerenderRoute;
914
- if (matches) {
915
- let newTracedFilesSize = group.pseudoLayerBytes;
916
- let newTracedFilesUncompressedSize = group.pseudoLayerUncompressedBytes;
917
- for (const newPage of newPages) {
918
- Object.keys(pageTraces[newPage] || {}).map(file => {
919
- if (!group.pseudoLayer[file]) {
920
- const item = tracedPseudoLayer[file];
921
- newTracedFilesSize += item.compBuffer?.byteLength || 0;
922
- newTracedFilesUncompressedSize += item.uncompressedSize || 0;
923
- }
924
- });
925
- newTracedFilesSize += compressedPages[newPage].compBuffer.byteLength;
926
- newTracedFilesUncompressedSize +=
927
- compressedPages[newPage].uncompressedSize;
928
- }
929
- const underUncompressedLimit = newTracedFilesUncompressedSize <
930
- exports.MAX_UNCOMPRESSED_LAMBDA_SIZE - LAMBDA_RESERVED_UNCOMPRESSED_SIZE;
931
- const underCompressedLimit = newTracedFilesSize <
932
- lambdaCompressedByteLimit - LAMBDA_RESERVED_COMPRESSED_SIZE;
933
- return underUncompressedLimit && underCompressedLimit;
934
- }
935
- return false;
936
- });
937
- if (matchingGroup) {
938
- matchingGroup.pages.push(page);
939
- }
940
- else {
941
- const newGroup = {
942
- pages: [page],
943
- ...opts,
944
- isPrerenders: isPrerenderRoute,
945
- isApiLambda: !!isApiPage(page),
946
- pseudoLayerBytes: initialPseudoLayer.pseudoLayerBytes,
947
- pseudoLayerUncompressedBytes: initialPseudoLayerUncompressed,
948
- pseudoLayer: Object.assign({}, initialPseudoLayer.pseudoLayer),
949
- };
950
- groups.push(newGroup);
951
- matchingGroup = newGroup;
952
- }
953
- for (const newPage of newPages) {
954
- Object.keys(pageTraces[newPage] || {}).map(file => {
955
- const pseudoItem = tracedPseudoLayer[file];
956
- const compressedSize = pseudoItem?.compBuffer?.byteLength || 0;
957
- if (!matchingGroup.pseudoLayer[file]) {
958
- matchingGroup.pseudoLayer[file] = pseudoItem;
959
- matchingGroup.pseudoLayerBytes += compressedSize;
960
- matchingGroup.pseudoLayerUncompressedBytes +=
961
- pseudoItem.uncompressedSize || 0;
962
- }
963
- });
964
- // ensure the page file itself is accounted for when grouping as
965
- // large pages can be created that can push the group over the limit
966
- matchingGroup.pseudoLayerBytes +=
967
- compressedPages[newPage].compBuffer.byteLength;
968
- matchingGroup.pseudoLayerUncompressedBytes +=
969
- compressedPages[newPage].uncompressedSize;
970
- }
971
- }
972
- return groups;
973
- }
974
- exports.getPageLambdaGroups = getPageLambdaGroups;
975
- const outputFunctionFileSizeInfo = (pages, pseudoLayer, pseudoLayerBytes, pseudoLayerUncompressedBytes, compressedPages) => {
976
- const exceededLimitOutput = [];
977
- console.log(`Serverless Function's page${pages.length === 1 ? '' : 's'}: ${pages.join(', ')}`);
978
- exceededLimitOutput.push([
979
- 'Large Dependencies',
980
- 'Uncompressed size',
981
- 'Compressed size',
982
- ]);
983
- const dependencies = {};
984
- for (const fileKey of Object.keys(pseudoLayer)) {
985
- if (!pseudoLayer[fileKey].isSymlink) {
986
- const fileItem = pseudoLayer[fileKey];
987
- const depKey = fileKey.split('/').slice(0, 3).join('/');
988
- if (!dependencies[depKey]) {
989
- dependencies[depKey] = {
990
- compressed: 0,
991
- uncompressed: 0,
992
- };
993
- }
994
- dependencies[depKey].compressed += fileItem.compBuffer.byteLength;
995
- dependencies[depKey].uncompressed += fileItem.uncompressedSize;
996
- }
997
- }
998
- for (const page of pages) {
999
- dependencies[`pages/${page}`] = {
1000
- compressed: compressedPages[page].compBuffer.byteLength,
1001
- uncompressed: compressedPages[page].uncompressedSize,
1002
- };
1003
- }
1004
- let numLargeDependencies = 0;
1005
- Object.keys(dependencies)
1006
- .sort((a, b) => {
1007
- // move largest dependencies to the top
1008
- const aDep = dependencies[a];
1009
- const bDep = dependencies[b];
1010
- if (aDep.compressed > bDep.compressed) {
1011
- return -1;
1012
- }
1013
- if (aDep.compressed < bDep.compressed) {
1014
- return 1;
1015
- }
1016
- return 0;
1017
- })
1018
- .forEach(depKey => {
1019
- const dep = dependencies[depKey];
1020
- if (dep.compressed < 100 * exports.KIB && dep.uncompressed < 500 * exports.KIB) {
1021
- // ignore smaller dependencies to reduce noise
1022
- return;
1023
- }
1024
- exceededLimitOutput.push([
1025
- depKey,
1026
- (0, exports.prettyBytes)(dep.uncompressed),
1027
- (0, exports.prettyBytes)(dep.compressed),
1028
- ]);
1029
- numLargeDependencies += 1;
1030
- });
1031
- if (numLargeDependencies === 0) {
1032
- exceededLimitOutput.push([
1033
- 'No large dependencies found (> 100KB compressed)',
1034
- ]);
1035
- }
1036
- exceededLimitOutput.push([]);
1037
- exceededLimitOutput.push([
1038
- 'All dependencies',
1039
- (0, exports.prettyBytes)(pseudoLayerUncompressedBytes),
1040
- (0, exports.prettyBytes)(pseudoLayerBytes),
1041
- ]);
1042
- console.log((0, text_table_1.default)(exceededLimitOutput, {
1043
- align: ['l', 'r', 'r'],
1044
- }));
1045
- };
1046
- exports.outputFunctionFileSizeInfo = outputFunctionFileSizeInfo;
1047
- const detectLambdaLimitExceeding = async (lambdaGroups, compressedSizeLimit, compressedPages) => {
1048
- // show debug info if within 5 MB of exceeding the limit
1049
- const COMPRESSED_SIZE_LIMIT_CLOSE = compressedSizeLimit - 5 * exports.MIB;
1050
- const UNCOMPRESSED_SIZE_LIMIT_CLOSE = exports.MAX_UNCOMPRESSED_LAMBDA_SIZE - 5 * exports.MIB;
1051
- let numExceededLimit = 0;
1052
- let numCloseToLimit = 0;
1053
- let loggedHeadInfo = false;
1054
- // pre-iterate to see if we are going to exceed the limit
1055
- // or only get close so our first log line can be correct
1056
- const filteredGroups = lambdaGroups.filter(group => {
1057
- const exceededLimit = group.pseudoLayerBytes > compressedSizeLimit ||
1058
- group.pseudoLayerUncompressedBytes > exports.MAX_UNCOMPRESSED_LAMBDA_SIZE;
1059
- const closeToLimit = group.pseudoLayerBytes > COMPRESSED_SIZE_LIMIT_CLOSE ||
1060
- group.pseudoLayerUncompressedBytes > UNCOMPRESSED_SIZE_LIMIT_CLOSE;
1061
- if (closeToLimit ||
1062
- exceededLimit ||
1063
- (0, build_utils_1.getPlatformEnv)('BUILDER_DEBUG') ||
1064
- process.env.NEXT_DEBUG_FUNCTION_SIZE) {
1065
- if (exceededLimit) {
1066
- numExceededLimit += 1;
1067
- }
1068
- if (closeToLimit) {
1069
- numCloseToLimit += 1;
1070
- }
1071
- return true;
1072
- }
1073
- });
1074
- for (const group of filteredGroups) {
1075
- if (!loggedHeadInfo) {
1076
- if (numExceededLimit || numCloseToLimit) {
1077
- console.log(`Warning: Max serverless function size of ${(0, exports.prettyBytes)(compressedSizeLimit)} compressed or ${(0, exports.prettyBytes)(exports.MAX_UNCOMPRESSED_LAMBDA_SIZE)} uncompressed${numExceededLimit ? '' : ' almost'} reached`);
1078
- }
1079
- else {
1080
- console.log(`Serverless function size info`);
1081
- }
1082
- loggedHeadInfo = true;
1083
- }
1084
- (0, exports.outputFunctionFileSizeInfo)(group.pages, group.pseudoLayer, group.pseudoLayerBytes, group.pseudoLayerUncompressedBytes, compressedPages);
1085
- }
1086
- if (numExceededLimit) {
1087
- console.log(`Max serverless function size was exceeded for ${numExceededLimit} function${numExceededLimit === 1 ? '' : 's'}`);
1088
- }
1089
- };
1090
- exports.detectLambdaLimitExceeding = detectLambdaLimitExceeding;
1091
- // checks if prerender files are all static or not before creating lambdas
1092
- const onPrerenderRouteInitial = (prerenderManifest, canUsePreviewMode, entryDirectory, nonLambdaSsgPages, routeKey, hasPages404, routesManifest, appDir) => {
1093
- let static404Page;
1094
- let static500Page;
1095
- // Get the route file as it'd be mounted in the builder output
1096
- const pr = prerenderManifest.staticRoutes[routeKey];
1097
- const { initialRevalidate, srcRoute, dataRoute } = pr;
1098
- const route = srcRoute || routeKey;
1099
- const isAppPathRoute = appDir && (!dataRoute || dataRoute?.endsWith('.rsc'));
1100
- const routeNoLocale = routesManifest?.i18n
1101
- ? normalizeLocalePath(routeKey, routesManifest.i18n.locales).pathname
1102
- : routeKey;
1103
- // if the 404 page used getStaticProps we need to update static404Page
1104
- // since it wasn't populated from the staticPages group
1105
- if (routeNoLocale === '/404') {
1106
- static404Page = path_1.default.posix.join(entryDirectory, routeKey);
1107
- }
1108
- if (routeNoLocale === '/500') {
1109
- static500Page = path_1.default.posix.join(entryDirectory, routeKey);
1110
- }
1111
- if (
1112
- // App paths must be Prerenders to ensure Vary header is
1113
- // correctly added
1114
- !isAppPathRoute &&
1115
- initialRevalidate === false &&
1116
- (!canUsePreviewMode || (hasPages404 && routeNoLocale === '/404')) &&
1117
- !prerenderManifest.fallbackRoutes[route] &&
1118
- !prerenderManifest.blockingFallbackRoutes[route]) {
1119
- if (routesManifest?.i18n &&
1120
- Object.keys(prerenderManifest.staticRoutes).some(route => {
1121
- const staticRoute = prerenderManifest.staticRoutes[route];
1122
- return (staticRoute.srcRoute === srcRoute &&
1123
- staticRoute.initialRevalidate !== false);
1124
- })) {
1125
- // if any locale static routes are using revalidate the page
1126
- // requires a lambda
1127
- return {
1128
- static404Page,
1129
- static500Page,
1130
- };
1131
- }
1132
- nonLambdaSsgPages.add(route === '/' ? '/index' : route);
1133
- }
1134
- return {
1135
- static404Page,
1136
- static500Page,
1137
- };
1138
- };
1139
- exports.onPrerenderRouteInitial = onPrerenderRouteInitial;
1140
- let prerenderGroup = 1;
1141
- const onPrerenderRoute = (prerenderRouteArgs) => (routeKey, { isBlocking, isFallback, isOmitted, locale, }) => {
1142
- const { appDir, pagesDir, static404Page, localePrefixed404, entryDirectory, prerenderManifest, isSharedLambdas, isServerMode, canUsePreviewMode, lambdas, prerenders, pageLambdaMap, routesManifest, isCorrectNotFoundRoutes, isEmptyAllowQueryForPrendered, } = prerenderRouteArgs;
1143
- if (isBlocking && isFallback) {
1144
- throw new build_utils_1.NowBuildError({
1145
- code: 'NEXT_ISBLOCKING_ISFALLBACK',
1146
- message: 'invariant: isBlocking and isFallback cannot both be true',
1147
- });
1148
- }
1149
- if (isFallback && isOmitted) {
1150
- throw new build_utils_1.NowBuildError({
1151
- code: 'NEXT_ISOMITTED_ISFALLBACK',
1152
- message: 'invariant: isOmitted and isFallback cannot both be true',
1153
- });
1154
- }
1155
- // Get the route file as it'd be mounted in the builder output
1156
- let routeFileNoExt = routeKey === '/' ? '/index' : routeKey;
1157
- let origRouteFileNoExt = routeFileNoExt;
1158
- const { isLocalePrefixed } = prerenderManifest;
1159
- if (!locale && isLocalePrefixed) {
1160
- const localePathResult = normalizeLocalePath(routeKey, routesManifest?.i18n?.locales || []);
1161
- locale = localePathResult.detectedLocale;
1162
- origRouteFileNoExt =
1163
- localePathResult.pathname === '/'
1164
- ? '/index'
1165
- : localePathResult.pathname;
1166
- }
1167
- const nonDynamicSsg = !isFallback &&
1168
- !isBlocking &&
1169
- !isOmitted &&
1170
- !prerenderManifest.staticRoutes[routeKey].srcRoute;
1171
- // if there isn't a srcRoute then it's a non-dynamic SSG page
1172
- if ((nonDynamicSsg && !isLocalePrefixed) || isFallback || isOmitted) {
1173
- routeFileNoExt = addLocaleOrDefault(
1174
- // root index files are located without folder/index.html
1175
- routeFileNoExt, routesManifest, locale);
1176
- }
1177
- const isNotFound = prerenderManifest.notFoundRoutes.includes(routeKey);
1178
- let initialRevalidate;
1179
- let srcRoute;
1180
- let dataRoute;
1181
- let initialStatus;
1182
- let initialHeaders;
1183
- let experimentalBypassFor;
1184
- if (isFallback || isBlocking) {
1185
- const pr = isFallback
1186
- ? prerenderManifest.fallbackRoutes[routeKey]
1187
- : prerenderManifest.blockingFallbackRoutes[routeKey];
1188
- initialRevalidate = 1; // TODO: should Next.js provide this default?
1189
- // @ts-ignore
1190
- if (initialRevalidate === false) {
1191
- // Lazy routes cannot be "snapshotted" in time.
1192
- throw new build_utils_1.NowBuildError({
1193
- code: 'NEXT_ISLAZY_INITIALREVALIDATE',
1194
- message: 'invariant isLazy: initialRevalidate !== false',
1195
- });
1196
- }
1197
- srcRoute = null;
1198
- dataRoute = pr.dataRoute;
1199
- experimentalBypassFor = pr.experimentalBypassFor;
1200
- }
1201
- else if (isOmitted) {
1202
- initialRevalidate = false;
1203
- srcRoute = routeKey;
1204
- dataRoute = prerenderManifest.omittedRoutes[routeKey].dataRoute;
1205
- experimentalBypassFor =
1206
- prerenderManifest.omittedRoutes[routeKey].experimentalBypassFor;
1207
- }
1208
- else {
1209
- const pr = prerenderManifest.staticRoutes[routeKey];
1210
- ({
1211
- initialRevalidate,
1212
- srcRoute,
1213
- dataRoute,
1214
- initialHeaders,
1215
- initialStatus,
1216
- experimentalBypassFor,
1217
- } = pr);
1218
- }
1219
- let isAppPathRoute = false;
1220
- // TODO: leverage manifest to determine app paths more accurately
1221
- if (appDir && srcRoute && (!dataRoute || dataRoute?.endsWith('.rsc'))) {
1222
- isAppPathRoute = true;
1223
- }
1224
- const isOmittedOrNotFound = isOmitted || isNotFound;
1225
- let htmlFsRef;
1226
- if (appDir && !dataRoute && isAppPathRoute && !(isBlocking || isFallback)) {
1227
- const contentType = initialHeaders?.['content-type'];
1228
- htmlFsRef = new build_utils_1.FileFsRef({
1229
- fsPath: path_1.default.join(appDir, `${routeFileNoExt}.body`),
1230
- contentType: contentType || 'text/html;charset=utf-8',
1231
- });
1232
- }
1233
- else {
1234
- htmlFsRef =
1235
- isBlocking || (isNotFound && !static404Page)
1236
- ? // Blocking pages do not have an HTML fallback
1237
- null
1238
- : new build_utils_1.FileFsRef({
1239
- fsPath: path_1.default.join(isAppPathRoute && !isOmittedOrNotFound && appDir
1240
- ? appDir
1241
- : pagesDir, isFallback
1242
- ? // Fallback pages have a special file.
1243
- addLocaleOrDefault(prerenderManifest.fallbackRoutes[routeKey].fallback, routesManifest, locale)
1244
- : // Otherwise, the route itself should exist as a static HTML
1245
- // file.
1246
- `${isOmittedOrNotFound
1247
- ? localePrefixed404
1248
- ? addLocaleOrDefault('/404', routesManifest, locale)
1249
- : '/404'
1250
- : routeFileNoExt}.html`),
1251
- });
1252
- }
1253
- const jsonFsRef =
1254
- // JSON data does not exist for fallback or blocking pages
1255
- isFallback || isBlocking || (isNotFound && !static404Page) || !dataRoute
1256
- ? null
1257
- : new build_utils_1.FileFsRef({
1258
- fsPath: path_1.default.join(isAppPathRoute && !isOmittedOrNotFound && appDir
1259
- ? appDir
1260
- : pagesDir, `${isOmittedOrNotFound
1261
- ? localePrefixed404
1262
- ? addLocaleOrDefault('/404.html', routesManifest, locale)
1263
- : '/404.html'
1264
- : isAppPathRoute
1265
- ? dataRoute
1266
- : routeFileNoExt + '.json'}`),
1267
- });
1268
- if (isOmittedOrNotFound) {
1269
- initialStatus = 404;
1270
- }
1271
- if (isAppPathRoute) {
1272
- // for literal index routes we need to append an additional /index
1273
- // due to the proxy's normalizing for /index routes
1274
- if (routeKey !== '/index' && routeKey.endsWith('/index')) {
1275
- routeKey = `${routeKey}/index`;
1276
- routeFileNoExt = routeKey;
1277
- origRouteFileNoExt = routeKey;
1278
- }
1279
- }
1280
- let outputPathPage = path_1.default.posix.join(entryDirectory, routeFileNoExt);
1281
- if (!isAppPathRoute) {
1282
- outputPathPage = normalizeIndexOutput(outputPathPage, isServerMode);
1283
- }
1284
- const outputPathPageOrig = path_1.default.posix.join(entryDirectory, origRouteFileNoExt);
1285
- let lambda;
1286
- let outputPathData = null;
1287
- if (dataRoute) {
1288
- outputPathData = path_1.default.posix.join(entryDirectory, dataRoute);
1289
- if (nonDynamicSsg || isFallback || isOmitted) {
1290
- outputPathData = outputPathData.replace(new RegExp(`${(0, escape_string_regexp_1.default)(origRouteFileNoExt)}.json$`),
1291
- // ensure we escape "$" correctly while replacing as "$" is a special
1292
- // character, we need to do double escaping as first is for the initial
1293
- // replace on the routeFile and then the second on the outputPath
1294
- `${routeFileNoExt.replace(/\$/g, '$$$$')}.json`);
1295
- }
1296
- }
1297
- if (isSharedLambdas) {
1298
- const outputSrcPathPage = normalizeIndexOutput(path_1.default.join('/', srcRoute == null
1299
- ? outputPathPageOrig
1300
- : path_1.default.posix.join(entryDirectory, srcRoute === '/' ? '/index' : srcRoute)), isServerMode);
1301
- const lambdaId = pageLambdaMap[outputSrcPathPage];
1302
- lambda = lambdas[lambdaId];
1303
- }
1304
- else {
1305
- const outputSrcPathPage = normalizeIndexOutput(srcRoute == null
1306
- ? outputPathPageOrig
1307
- : path_1.default.posix.join(entryDirectory, srcRoute === '/' ? '/index' : srcRoute), isServerMode);
1308
- lambda = lambdas[outputSrcPathPage];
1309
- }
1310
- if (!isAppPathRoute && !isNotFound && initialRevalidate === false) {
1311
- if (htmlFsRef == null || jsonFsRef == null) {
1312
- throw new build_utils_1.NowBuildError({
1313
- code: 'NEXT_HTMLFSREF_JSONFSREF',
1314
- message: `invariant: htmlFsRef != null && jsonFsRef != null ${routeFileNoExt}`,
1315
- });
1316
- }
1317
- // if preview mode/On-Demand ISR can't be leveraged
1318
- // we can output pure static outputs instead of prerenders
1319
- if (!canUsePreviewMode ||
1320
- (routeKey === '/404' && !lambdas[outputPathPage])) {
1321
- htmlFsRef.contentType = _1.htmlContentType;
1322
- prerenders[outputPathPage] = htmlFsRef;
1323
- if (outputPathData) {
1324
- prerenders[outputPathData] = jsonFsRef;
1325
- }
1326
- }
1327
- }
1328
- const isNotFoundPreview = isCorrectNotFoundRoutes &&
1329
- !initialRevalidate &&
1330
- canUsePreviewMode &&
1331
- isServerMode &&
1332
- isNotFound;
1333
- if (prerenders[outputPathPage] == null &&
1334
- (!isNotFound || initialRevalidate || isNotFoundPreview)) {
1335
- if (lambda == null) {
1336
- throw new build_utils_1.NowBuildError({
1337
- code: 'NEXT_MISSING_LAMBDA',
1338
- message: `Unable to find lambda for route: ${routeFileNoExt}`,
1339
- });
1340
- }
1341
- // `allowQuery` is an array of query parameter keys that are allowed for
1342
- // a given path. All other query keys will be striped. We can automatically
1343
- // detect this for prerender (ISR) pages by reading the routes manifest file.
1344
- const pageKey = srcRoute || routeKey;
1345
- const route = routesManifest?.dynamicRoutes.find((r) => r.page === pageKey && !('isMiddleware' in r));
1346
- const routeKeys = route?.routeKeys;
1347
- // by default allowQuery should be undefined and only set when
1348
- // we have sufficient information to set it
1349
- let allowQuery;
1350
- if (isEmptyAllowQueryForPrendered) {
1351
- const isDynamic = isDynamicRoute(routeKey);
1352
- if (!isDynamic) {
1353
- // for non-dynamic routes we use an empty array since
1354
- // no query values bust the cache for non-dynamic prerenders
1355
- // prerendered paths also do not pass allowQuery as they match
1356
- // during handle: 'filesystem' so should not cache differently
1357
- // by query values
1358
- allowQuery = [];
1359
- }
1360
- else if (routeKeys) {
1361
- // if we have routeKeys in the routes-manifest we use those
1362
- // for allowQuery for dynamic routes
1363
- allowQuery = Object.values(routeKeys);
1364
- }
1365
- }
1366
- else {
1367
- const isDynamic = isDynamicRoute(pageKey);
1368
- if (routeKeys) {
1369
- // if we have routeKeys in the routes-manifest we use those
1370
- // for allowQuery for dynamic routes
1371
- allowQuery = Object.values(routeKeys);
1372
- }
1373
- else if (!isDynamic) {
1374
- // for non-dynamic routes we use an empty array since
1375
- // no query values bust the cache for non-dynamic prerenders
1376
- allowQuery = [];
1377
- }
1378
- }
1379
- const rscEnabled = !!routesManifest?.rsc;
1380
- const rscVaryHeader = routesManifest?.rsc?.varyHeader ||
1381
- 'RSC, Next-Router-State-Tree, Next-Router-Prefetch';
1382
- const rscContentTypeHeader = routesManifest?.rsc?.contentTypeHeader || exports.RSC_CONTENT_TYPE;
1383
- let sourcePath;
1384
- if (`/${outputPathPage}` !== srcRoute && srcRoute) {
1385
- sourcePath = srcRoute;
1386
- }
1387
- prerenders[outputPathPage] = new build_utils_1.Prerender({
1388
- expiration: initialRevalidate,
1389
- lambda,
1390
- allowQuery,
1391
- fallback: htmlFsRef,
1392
- group: prerenderGroup,
1393
- bypassToken: prerenderManifest.bypassToken,
1394
- experimentalBypassFor,
1395
- initialStatus,
1396
- initialHeaders,
1397
- sourcePath,
1398
- ...(isNotFound
1399
- ? {
1400
- initialStatus: 404,
1401
- }
1402
- : {}),
1403
- ...(rscEnabled
1404
- ? {
1405
- initialHeaders: {
1406
- ...initialHeaders,
1407
- vary: rscVaryHeader,
1408
- },
1409
- }
1410
- : {}),
1411
- });
1412
- if (outputPathData) {
1413
- prerenders[outputPathData] = new build_utils_1.Prerender({
1414
- expiration: initialRevalidate,
1415
- lambda,
1416
- allowQuery,
1417
- fallback: jsonFsRef,
1418
- group: prerenderGroup,
1419
- bypassToken: prerenderManifest.bypassToken,
1420
- experimentalBypassFor,
1421
- ...(isNotFound
1422
- ? {
1423
- initialStatus: 404,
1424
- }
1425
- : {}),
1426
- ...(rscEnabled
1427
- ? {
1428
- initialHeaders: {
1429
- 'content-type': rscContentTypeHeader,
1430
- vary: rscVaryHeader,
1431
- },
1432
- }
1433
- : {}),
1434
- });
1435
- }
1436
- ++prerenderGroup;
1437
- if (routesManifest?.i18n && isBlocking) {
1438
- for (const locale of routesManifest.i18n.locales) {
1439
- const localeRouteFileNoExt = addLocaleOrDefault(routeFileNoExt, routesManifest, locale);
1440
- const localeOutputPathPage = normalizeIndexOutput(path_1.default.posix.join(entryDirectory, localeRouteFileNoExt), isServerMode);
1441
- const origPrerenderPage = prerenders[outputPathPage];
1442
- prerenders[localeOutputPathPage] = {
1443
- ...origPrerenderPage,
1444
- group: prerenderGroup,
1445
- };
1446
- if (outputPathData) {
1447
- const localeOutputPathData = outputPathData.replace(new RegExp(`${(0, escape_string_regexp_1.default)(origRouteFileNoExt)}.json$`), `${localeRouteFileNoExt}${localeRouteFileNoExt !== origRouteFileNoExt &&
1448
- origRouteFileNoExt === '/index'
1449
- ? '/index'
1450
- : ''}.json`);
1451
- const origPrerenderData = prerenders[outputPathData];
1452
- prerenders[localeOutputPathData] = {
1453
- ...origPrerenderData,
1454
- group: prerenderGroup,
1455
- };
1456
- }
1457
- ++prerenderGroup;
1458
- }
1459
- }
1460
- }
1461
- if (((nonDynamicSsg && !isLocalePrefixed) || isFallback || isOmitted) &&
1462
- routesManifest?.i18n &&
1463
- !locale) {
1464
- // load each locale
1465
- for (const locale of routesManifest.i18n.locales) {
1466
- if (locale === routesManifest.i18n.defaultLocale)
1467
- continue;
1468
- (0, exports.onPrerenderRoute)(prerenderRouteArgs)(routeKey, {
1469
- isBlocking,
1470
- isFallback,
1471
- isOmitted,
1472
- locale,
1473
- });
1474
- }
1475
- }
1476
- };
1477
- exports.onPrerenderRoute = onPrerenderRoute;
1478
- async function getStaticFiles(entryPath, entryDirectory, outputDirectory) {
1479
- const collectLabel = 'Collected static files (public/, static/, .next/static)';
1480
- console.time(collectLabel);
1481
- const nextStaticFiles = await (0, build_utils_1.glob)('**', path_1.default.join(entryPath, outputDirectory, 'static'));
1482
- const staticFolderFiles = await (0, build_utils_1.glob)('**', path_1.default.join(entryPath, 'static'));
1483
- let publicFolderFiles = {};
1484
- let publicFolderPath;
1485
- if (await fs_extra_1.default.pathExists(path_1.default.join(entryPath, 'public'))) {
1486
- publicFolderPath = path_1.default.join(entryPath, 'public');
1487
- }
1488
- else if (
1489
- // check at the same level as the output directory also
1490
- await fs_extra_1.default.pathExists(path_1.default.join(entryPath, outputDirectory, '../public'))) {
1491
- publicFolderPath = path_1.default.join(entryPath, outputDirectory, '../public');
1492
- }
1493
- if (publicFolderPath) {
1494
- (0, build_utils_1.debug)(`Using public folder at ${publicFolderPath}`);
1495
- publicFolderFiles = await (0, build_utils_1.glob)('**/*', publicFolderPath);
1496
- }
1497
- else {
1498
- (0, build_utils_1.debug)('No public folder found');
1499
- }
1500
- const staticFiles = {};
1501
- const staticDirectoryFiles = {};
1502
- const publicDirectoryFiles = {};
1503
- for (const file of Object.keys(nextStaticFiles)) {
1504
- staticFiles[path_1.default.posix.join(entryDirectory, `_next/static/${file}`)] =
1505
- nextStaticFiles[file];
1506
- }
1507
- for (const file of Object.keys(staticFolderFiles)) {
1508
- staticDirectoryFiles[path_1.default.posix.join(entryDirectory, 'static', file)] =
1509
- staticFolderFiles[file];
1510
- }
1511
- for (const file of Object.keys(publicFolderFiles)) {
1512
- publicDirectoryFiles[path_1.default.posix.join(entryDirectory, file)] =
1513
- publicFolderFiles[file];
1514
- }
1515
- console.timeEnd(collectLabel);
1516
- return {
1517
- staticFiles,
1518
- staticDirectoryFiles,
1519
- publicDirectoryFiles,
1520
- };
1521
- }
1522
- exports.getStaticFiles = getStaticFiles;
1523
- function normalizeIndexOutput(outputName, isServerMode) {
1524
- if (outputName !== 'index' && outputName !== '/index' && isServerMode) {
1525
- return outputName.replace(/\/index$/, '');
1526
- }
1527
- return outputName;
1528
- }
1529
- exports.normalizeIndexOutput = normalizeIndexOutput;
1530
- /**
1531
- * The path to next-server was changed in
1532
- * https://github.com/vercel/next.js/pull/26756
1533
- */
1534
- function getNextServerPath(nextVersion) {
1535
- return semver_1.default.gte(nextVersion, 'v11.0.2-canary.4')
1536
- ? 'next/dist/server'
1537
- : 'next/dist/next-server/server';
1538
- }
1539
- exports.getNextServerPath = getNextServerPath;
1540
- // update to leverage
1541
- function updateRouteSrc(route, index, manifestItems) {
1542
- if (route.src) {
1543
- route.src = manifestItems[index].regex;
1544
- }
1545
- return route;
1546
- }
1547
- exports.updateRouteSrc = updateRouteSrc;
1548
- async function getPrivateOutputs(dir, entries) {
1549
- const files = {};
1550
- const routes = [];
1551
- for (const [existingFile, outputFile] of Object.entries(entries)) {
1552
- const fsPath = path_1.default.join(dir, existingFile);
1553
- try {
1554
- const { mode, size } = await (0, fs_extra_1.stat)(fsPath);
1555
- if (size > 30 * 1024 * 1024) {
1556
- throw new Error(`Exceeds maximum file size: ${size}`);
1557
- }
1558
- files[outputFile] = new build_utils_1.FileFsRef({ mode, fsPath });
1559
- routes.push({
1560
- src: `/${outputFile}`,
1561
- dest: '/404',
1562
- status: 404,
1563
- continue: true,
1564
- });
1565
- }
1566
- catch (error) {
1567
- (0, build_utils_1.debug)(`Private file ${existingFile} had an error and will not be uploaded: ${error}`);
1568
- }
1569
- }
1570
- return { files, routes };
1571
- }
1572
- exports.getPrivateOutputs = getPrivateOutputs;
1573
- const vercelFunctionRegionsVar = process.env.VERCEL_FUNCTION_REGIONS;
1574
- let vercelFunctionRegions;
1575
- if (vercelFunctionRegionsVar) {
1576
- vercelFunctionRegions = vercelFunctionRegionsVar.split(',');
1577
- }
1578
- /**
1579
- * Normalizes the regions config that comes from the Next.js edge functions manifest.
1580
- * Ensures that config like `home` and `global` are converted to the corresponding Vercel region config.
1581
- * In the future we'll want to make `home` and `global` part of the Build Output API.
1582
- * - `home` refers to the regions set in vercel.json or on the Vercel dashboard project config.
1583
- * - `global` refers to all regions.
1584
- */
1585
- function normalizeRegions(regions) {
1586
- if (typeof regions === 'string') {
1587
- regions = [regions];
1588
- }
1589
- const newRegions = [];
1590
- for (const region of regions) {
1591
- // Explicitly mentioned as `home` is one of the explicit values for preferredRegion in Next.js.
1592
- if (region === 'home') {
1593
- if (vercelFunctionRegions) {
1594
- // Includes the regions from the VERCEL_FUNCTION_REGIONS env var.
1595
- newRegions.push(...vercelFunctionRegions);
1596
- }
1597
- continue;
1598
- }
1599
- // Explicitly mentioned as `global` is one of the explicit values for preferredRegion in Next.js.
1600
- if (region === 'global') {
1601
- // Uses `all` instead as that's how it's implemented on Vercel.
1602
- // Returns here as when all is provided all regions will be matched.
1603
- return 'all';
1604
- }
1605
- // Explicitly mentioned as `auto` is one of the explicit values for preferredRegion in Next.js.
1606
- if (region === 'auto') {
1607
- // Returns here as when auto is provided all regions will be matched.
1608
- return 'auto';
1609
- }
1610
- newRegions.push(region);
1611
- }
1612
- // Ensure we don't pass an empty array as that is not supported.
1613
- if (newRegions.length === 0) {
1614
- return undefined;
1615
- }
1616
- return newRegions;
1617
- }
1618
- function normalizeEdgeFunctionPath(shortPath, appPathRoutesManifest) {
1619
- if (shortPath.startsWith('app/') &&
1620
- (shortPath.endsWith('/page') ||
1621
- shortPath.endsWith('/route') ||
1622
- shortPath === 'app/_not-found')) {
1623
- const ogRoute = shortPath.replace(/^app\//, '/');
1624
- shortPath = (appPathRoutesManifest[ogRoute] ||
1625
- shortPath.replace(/(^|\/)(page|route)$/, '')).replace(/^\//, '');
1626
- if (!shortPath || shortPath === '/') {
1627
- shortPath = 'index';
1628
- }
1629
- }
1630
- return shortPath;
1631
- }
1632
- exports.normalizeEdgeFunctionPath = normalizeEdgeFunctionPath;
1633
- async function getMiddlewareBundle({ entryPath, outputDirectory, routesManifest, isCorrectMiddlewareOrder, prerenderBypassToken, nextVersion, appPathRoutesManifest, }) {
1634
- const middlewareManifest = await getMiddlewareManifest(entryPath, outputDirectory);
1635
- const sortedFunctions = [
1636
- ...(!middlewareManifest
1637
- ? []
1638
- : middlewareManifest.sortedMiddleware.map(key => ({
1639
- key,
1640
- edgeFunction: middlewareManifest?.middleware[key],
1641
- type: 'middleware',
1642
- }))),
1643
- ...Object.entries(middlewareManifest?.functions ?? {}).map(([key, edgeFunction]) => {
1644
- return {
1645
- key,
1646
- edgeFunction,
1647
- type: 'function',
1648
- };
1649
- }),
1650
- ];
1651
- if (middlewareManifest && sortedFunctions.length > 0) {
1652
- const workerConfigs = await Promise.all(sortedFunctions.map(async ({ key, edgeFunction, type }) => {
1653
- try {
1654
- const wrappedModuleSource = await (0, get_edge_function_source_1.getNextjsEdgeFunctionSource)(edgeFunction.files, {
1655
- name: edgeFunction.name,
1656
- staticRoutes: routesManifest.staticRoutes,
1657
- dynamicRoutes: routesManifest.dynamicRoutes.filter(r => !('isMiddleware' in r)),
1658
- nextConfig: {
1659
- basePath: routesManifest.basePath,
1660
- i18n: routesManifest.i18n,
1661
- },
1662
- }, path_1.default.resolve(entryPath, outputDirectory), edgeFunction.wasm);
1663
- return {
1664
- type,
1665
- page: edgeFunction.page,
1666
- edgeFunction: (() => {
1667
- const { source, map } = wrappedModuleSource.sourceAndMap();
1668
- const transformedMap = (0, sourcemapped_1.stringifySourceMap)(transformSourceMap(map));
1669
- const wasmFiles = (edgeFunction.wasm ?? []).reduce((acc, { filePath, name }) => {
1670
- const fullFilePath = path_1.default.join(entryPath, outputDirectory, filePath);
1671
- acc[`wasm/${name}.wasm`] = new build_utils_1.FileFsRef({
1672
- mode: 0o644,
1673
- contentType: 'application/wasm',
1674
- fsPath: fullFilePath,
1675
- });
1676
- return acc;
1677
- }, {});
1678
- const assetFiles = (edgeFunction.assets ?? []).reduce((acc, { filePath, name }) => {
1679
- const fullFilePath = path_1.default.join(entryPath, outputDirectory, filePath);
1680
- acc[`assets/${name}`] = new build_utils_1.FileFsRef({
1681
- mode: 0o644,
1682
- contentType: 'application/octet-stream',
1683
- fsPath: fullFilePath,
1684
- });
1685
- return acc;
1686
- }, {});
1687
- return new build_utils_1.EdgeFunction({
1688
- deploymentTarget: 'v8-worker',
1689
- name: edgeFunction.name,
1690
- files: {
1691
- 'index.js': new build_utils_1.FileBlob({
1692
- data: source,
1693
- contentType: 'application/javascript',
1694
- mode: 0o644,
1695
- }),
1696
- ...(transformedMap && {
1697
- 'index.js.map': new build_utils_1.FileBlob({
1698
- data: transformedMap,
1699
- contentType: 'application/json',
1700
- mode: 0o644,
1701
- }),
1702
- }),
1703
- ...wasmFiles,
1704
- ...assetFiles,
1705
- },
1706
- regions: edgeFunction.regions
1707
- ? normalizeRegions(edgeFunction.regions)
1708
- : undefined,
1709
- entrypoint: 'index.js',
1710
- assets: (edgeFunction.assets ?? []).map(({ name }) => {
1711
- return {
1712
- name,
1713
- path: `assets/${name}`,
1714
- };
1715
- }),
1716
- framework: {
1717
- slug: 'nextjs',
1718
- version: nextVersion,
1719
- },
1720
- });
1721
- })(),
1722
- routeMatchers: getRouteMatchers(edgeFunction, routesManifest),
1723
- };
1724
- }
1725
- catch (e) {
1726
- e.message = `Can't build edge function ${key}: ${e.message}`;
1727
- throw e;
1728
- }
1729
- }));
1730
- const source = {
1731
- staticRoutes: [],
1732
- dynamicRouteMap: new Map(),
1733
- edgeFunctions: {},
1734
- };
1735
- for (const worker of workerConfigs.values()) {
1736
- const edgeFile = worker.edgeFunction.name;
1737
- let shortPath = edgeFile;
1738
- // Replacing the folder prefix for the page
1739
- //
1740
- // For `pages/`, use file base name directly:
1741
- // pages/index -> index
1742
- // For `app/`, use folder name, handle the root page as index:
1743
- // app/route/page -> route
1744
- // app/page -> index
1745
- // app/index/page -> index/index
1746
- if (shortPath.startsWith('pages/')) {
1747
- shortPath = shortPath.replace(/^pages\//, '');
1748
- }
1749
- else {
1750
- shortPath = normalizeEdgeFunctionPath(shortPath, appPathRoutesManifest);
1751
- }
1752
- if (routesManifest?.basePath) {
1753
- shortPath = normalizeIndexOutput(path_1.default.posix.join('./', routesManifest?.basePath, shortPath.replace(/^\//, '')), true);
1754
- }
1755
- worker.edgeFunction.name = shortPath;
1756
- source.edgeFunctions[shortPath] = worker.edgeFunction;
1757
- // we don't add the route for edge functions as these
1758
- // are already added in the routes-manifest under dynamicRoutes
1759
- if (worker.type === 'function') {
1760
- continue;
1761
- }
1762
- for (const matcher of worker.routeMatchers) {
1763
- const route = {
1764
- continue: true,
1765
- src: matcher.regexp,
1766
- has: matcher.has,
1767
- missing: [
1768
- {
1769
- type: 'header',
1770
- key: 'x-prerender-revalidate',
1771
- value: prerenderBypassToken,
1772
- },
1773
- ...(matcher.missing || []),
1774
- ],
1775
- };
1776
- route.middlewarePath = shortPath;
1777
- route.middlewareRawSrc = matcher.originalSource
1778
- ? [matcher.originalSource]
1779
- : [];
1780
- if (isCorrectMiddlewareOrder) {
1781
- route.override = true;
1782
- }
1783
- if (routesManifest.version > 3 && isDynamicRoute(worker.page)) {
1784
- source.dynamicRouteMap.set(worker.page, route);
1785
- }
1786
- else {
1787
- source.staticRoutes.push(route);
1788
- }
1789
- }
1790
- }
1791
- return source;
1792
- }
1793
- return {
1794
- staticRoutes: [],
1795
- dynamicRouteMap: new Map(),
1796
- edgeFunctions: {},
1797
- };
1798
- }
1799
- exports.getMiddlewareBundle = getMiddlewareBundle;
1800
- /**
1801
- * Attempts to read the functions config manifest from the pre-defined
1802
- * location. If the manifest can't be found it will resolve to
1803
- * undefined.
1804
- */
1805
- async function getFunctionsConfigManifest(entryPath, outputDirectory) {
1806
- const functionConfigManifestPath = path_1.default.join(entryPath, outputDirectory, './server/functions-config-manifest.json');
1807
- const hasManifest = await fs_extra_1.default
1808
- .access(functionConfigManifestPath)
1809
- .then(() => true)
1810
- .catch(() => false);
1811
- if (!hasManifest) {
1812
- return;
1813
- }
1814
- const manifest = await fs_extra_1.default.readJSON(functionConfigManifestPath);
1815
- return manifest.version === 1 ? manifest : undefined;
1816
- }
1817
- exports.getFunctionsConfigManifest = getFunctionsConfigManifest;
1818
- /**
1819
- * Attempts to read the middleware manifest from the pre-defined
1820
- * location. If the manifest can't be found it will resolve to
1821
- * undefined.
1822
- */
1823
- async function getMiddlewareManifest(entryPath, outputDirectory) {
1824
- const middlewareManifestPath = path_1.default.join(entryPath, outputDirectory, './server/middleware-manifest.json');
1825
- const hasManifest = await fs_extra_1.default
1826
- .access(middlewareManifestPath)
1827
- .then(() => true)
1828
- .catch(() => false);
1829
- if (!hasManifest) {
1830
- return;
1831
- }
1832
- const manifest = (await fs_extra_1.default.readJSON(middlewareManifestPath));
1833
- return manifest.version === 1
1834
- ? upgradeMiddlewareManifest(manifest)
1835
- : manifest;
1836
- }
1837
- exports.getMiddlewareManifest = getMiddlewareManifest;
1838
- function upgradeMiddlewareManifest(v1) {
1839
- function updateInfo(v1Info) {
1840
- const { regexp, ...rest } = v1Info;
1841
- return {
1842
- ...rest,
1843
- matchers: [{ regexp }],
1844
- };
1845
- }
1846
- const middleware = Object.fromEntries(Object.entries(v1.middleware).map(([p, info]) => [p, updateInfo(info)]));
1847
- const functions = v1.functions
1848
- ? Object.fromEntries(Object.entries(v1.functions).map(([p, info]) => [p, updateInfo(info)]))
1849
- : undefined;
1850
- return {
1851
- ...v1,
1852
- version: 2,
1853
- middleware,
1854
- functions,
1855
- };
1856
- }
1857
- exports.upgradeMiddlewareManifest = upgradeMiddlewareManifest;
1858
- /**
1859
- * For an object containing middleware info and a routes manifest this will
1860
- * generate a string with the route that will activate the middleware on
1861
- * Vercel Proxy.
1862
- *
1863
- * @param param0 The middleware info including matchers and page.
1864
- * @param param1 The routes manifest
1865
- * @returns matchers for the middleware route.
1866
- */
1867
- function getRouteMatchers(info, { basePath = '', i18n }) {
1868
- function getRegexp(regexp) {
1869
- if (info.page === '/') {
1870
- return regexp;
1871
- }
1872
- const locale = i18n?.locales.length
1873
- ? `(?:/(${i18n.locales
1874
- .map(locale => (0, escape_string_regexp_1.default)(locale))
1875
- .join('|')}))?`
1876
- : '';
1877
- return `(?:^${basePath}${locale}${regexp.substring(1)})`;
1878
- }
1879
- function normalizeHas(has) {
1880
- return has.map(v => v.type === 'header'
1881
- ? {
1882
- ...v,
1883
- key: v.key.toLowerCase(),
1884
- }
1885
- : v);
1886
- }
1887
- return info.matchers.map(matcher => {
1888
- const m = {
1889
- regexp: getRegexp(matcher.regexp),
1890
- originalSource: matcher.originalSource,
1891
- };
1892
- if (matcher.has) {
1893
- m.has = normalizeHas(matcher.has);
1894
- }
1895
- if (matcher.missing) {
1896
- m.missing = normalizeHas(matcher.missing);
1897
- }
1898
- return m;
1899
- });
1900
- }
1901
- /**
1902
- * Makes the sources more human-readable in the source map
1903
- * by removing webpack-specific prefixes
1904
- */
1905
- function transformSourceMap(sourcemap) {
1906
- if (!sourcemap)
1907
- return;
1908
- const sources = sourcemap.sources
1909
- ?.map(source => {
1910
- return source.replace(/^webpack:\/\/?_N_E\/(?:\.\/)?/, '');
1911
- })
1912
- // Hide the Next.js entrypoint
1913
- .map(source => {
1914
- return source.startsWith('?') ? '[native code]' : source;
1915
- });
1916
- return { ...sourcemap, sources };
1917
- }
1918
- function getOperationType({ group, prerenderManifest, pageFileName, }) {
1919
- if (group?.isApiLambda || isApiPage(pageFileName)) {
1920
- return 'API';
1921
- }
1922
- if (group?.isPrerenders) {
1923
- return 'ISR';
1924
- }
1925
- if (pageFileName && prerenderManifest) {
1926
- const { blockingFallbackRoutes = {}, fallbackRoutes = {} } = prerenderManifest;
1927
- if (pageFileName in blockingFallbackRoutes ||
1928
- pageFileName in fallbackRoutes) {
1929
- return 'ISR';
1930
- }
1931
- }
1932
- return 'Page'; // aka SSR
1933
- }
1934
- exports.getOperationType = getOperationType;
1935
- function isApiPage(page) {
1936
- if (!page) {
1937
- return false;
1938
- }
1939
- return page
1940
- .replace(/\\/g, '/')
1941
- .match(/(serverless|server)\/pages\/api(\/|\.js$)/);
1942
- }
1943
- exports.isApiPage = isApiPage;