642 lines
32 KiB
JavaScript
Executable File
642 lines
32 KiB
JavaScript
Executable File
"use strict";
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
0 && (module.exports = {
|
|
assignErrorIfEmpty: null,
|
|
buildAppStaticPaths: null,
|
|
calculateFallbackMode: null,
|
|
filterUniqueParams: null,
|
|
generateAllParamCombinations: null,
|
|
generateRouteStaticParams: null
|
|
});
|
|
function _export(target, all) {
|
|
for(var name in all)Object.defineProperty(target, name, {
|
|
enumerable: true,
|
|
get: all[name]
|
|
});
|
|
}
|
|
_export(exports, {
|
|
assignErrorIfEmpty: function() {
|
|
return assignErrorIfEmpty;
|
|
},
|
|
buildAppStaticPaths: function() {
|
|
return buildAppStaticPaths;
|
|
},
|
|
calculateFallbackMode: function() {
|
|
return calculateFallbackMode;
|
|
},
|
|
filterUniqueParams: function() {
|
|
return filterUniqueParams;
|
|
},
|
|
generateAllParamCombinations: function() {
|
|
return generateAllParamCombinations;
|
|
},
|
|
generateRouteStaticParams: function() {
|
|
return generateRouteStaticParams;
|
|
}
|
|
});
|
|
const _nodepath = /*#__PURE__*/ _interop_require_default(require("node:path"));
|
|
const _runwithafter = require("../../server/after/run-with-after");
|
|
const _workstore = require("../../server/async-storage/work-store");
|
|
const _fallback = require("../../lib/fallback");
|
|
const _routematcher = require("../../shared/lib/router/utils/route-matcher");
|
|
const _routeregex = require("../../shared/lib/router/utils/route-regex");
|
|
const _utils = require("./utils");
|
|
const _escapepathdelimiters = /*#__PURE__*/ _interop_require_default(require("../../shared/lib/router/utils/escape-path-delimiters"));
|
|
const _createincrementalcache = require("../../export/helpers/create-incremental-cache");
|
|
function _interop_require_default(obj) {
|
|
return obj && obj.__esModule ? obj : {
|
|
default: obj
|
|
};
|
|
}
|
|
function filterUniqueParams(routeParamKeys, routeParams) {
|
|
// A Map is used to store unique parameter combinations. The key of the Map
|
|
// is a string representation of the parameter combination, and the value
|
|
// is the actual `Params` object.
|
|
const unique = new Map();
|
|
// Iterate over each parameter object in the input array.
|
|
for (const params of routeParams){
|
|
let key = '' // Initialize an empty string to build the unique key for the current `params` object.
|
|
;
|
|
// Iterate through the `routeParamKeys` (which are assumed to be sorted).
|
|
// This consistent order is crucial for generating a stable and unique key
|
|
// for each parameter combination.
|
|
for (const paramKey of routeParamKeys){
|
|
const value = params[paramKey];
|
|
// Construct a part of the key using the parameter key and its value.
|
|
// A type prefix (`A:` for Array, `S:` for String, `U:` for undefined) is added to the value
|
|
// to prevent collisions. For example, `['a', 'b']` and `'a,b'` would
|
|
// otherwise generate the same string representation, leading to incorrect
|
|
// deduplication. This ensures that different types with the same string
|
|
// representation are treated as distinct.
|
|
let valuePart;
|
|
if (Array.isArray(value)) {
|
|
valuePart = `A:${value.join(',')}`;
|
|
} else if (value === undefined) {
|
|
valuePart = `U:undefined`;
|
|
} else {
|
|
valuePart = `S:${value}`;
|
|
}
|
|
key += `${paramKey}:${valuePart}|`;
|
|
}
|
|
// If the generated key is not already in the `unique` Map, it means this
|
|
// parameter combination is unique so far. Add it to the Map.
|
|
if (!unique.has(key)) {
|
|
unique.set(key, params);
|
|
}
|
|
}
|
|
// Convert the Map's values (the unique `Params` objects) back into an array
|
|
// and return it.
|
|
return Array.from(unique.values());
|
|
}
|
|
function generateAllParamCombinations(routeParamKeys, routeParams, rootParamKeys) {
|
|
// A Map is used to store unique combinations of Route Parameters.
|
|
// The key of the Map is a string representation of the Route Parameter
|
|
// combination, and the value is the `Params` object containing only
|
|
// the Route Parameters.
|
|
const combinations = new Map();
|
|
// Determine the minimum index where all Root Parameters are included.
|
|
// This optimization ensures we only generate combinations that include
|
|
// a complete set of Root Parameters, preventing invalid Static Shells.
|
|
//
|
|
// For example, if rootParamKeys = ['lang', 'region'] and routeParamKeys = ['lang', 'region', 'slug']:
|
|
// - 'lang' is at index 0, 'region' is at index 1
|
|
// - minIndexForCompleteRootParams = max(0, 1) = 1
|
|
// - We'll only generate combinations starting from index 1 (which includes both lang and region)
|
|
let minIndexForCompleteRootParams = -1;
|
|
if (rootParamKeys.length > 0) {
|
|
// Find the index of the last Root Parameter in routeParamKeys.
|
|
// This tells us the minimum combination length needed to include all Root Parameters.
|
|
for (const rootParamKey of rootParamKeys){
|
|
const index = routeParamKeys.indexOf(rootParamKey);
|
|
if (index === -1) {
|
|
// Root Parameter not found in Route Parameters - this shouldn't happen in normal cases
|
|
// but we handle it gracefully by treating it as if there are no Root Parameters.
|
|
// This allows the function to fall back to generating all sub-combinations.
|
|
minIndexForCompleteRootParams = -1;
|
|
break;
|
|
}
|
|
// Track the highest index among all Root Parameters.
|
|
// This ensures all Root Parameters are included in any generated combination.
|
|
minIndexForCompleteRootParams = Math.max(minIndexForCompleteRootParams, index);
|
|
}
|
|
}
|
|
// Iterate over each Static Parameter object in the input array.
|
|
// Each params object represents one potential route combination (e.g., { lang: 'en', region: 'US', slug: 'home' })
|
|
for (const params of routeParams){
|
|
// Generate all possible prefix combinations for this Static Parameter set.
|
|
// For routeParamKeys = ['lang', 'region', 'slug'], we'll generate combinations at:
|
|
// - i=0: { lang: 'en' }
|
|
// - i=1: { lang: 'en', region: 'US' }
|
|
// - i=2: { lang: 'en', region: 'US', slug: 'home' }
|
|
//
|
|
// The iteration order is crucial for generating stable and unique keys
|
|
// for each Route Parameter combination.
|
|
for(let i = 0; i < routeParamKeys.length; i++){
|
|
// Skip generating combinations that don't include all Root Parameters.
|
|
// This prevents creating invalid Static Shells that are missing required Root Parameters.
|
|
//
|
|
// For example, if Root Parameters are ['lang', 'region'] and minIndexForCompleteRootParams = 1:
|
|
// - Skip i=0 (would only include 'lang', missing 'region')
|
|
// - Process i=1 and higher (includes both 'lang' and 'region')
|
|
if (minIndexForCompleteRootParams >= 0 && i < minIndexForCompleteRootParams) {
|
|
continue;
|
|
}
|
|
// Initialize data structures for building this specific combination
|
|
const combination = {};
|
|
const keyParts = [];
|
|
let hasAllRootParams = true;
|
|
// Build the sub-combination with parameters from index 0 to i (inclusive).
|
|
// This creates a prefix of the full parameter set, building up combinations incrementally.
|
|
//
|
|
// For example, if routeParamKeys = ['lang', 'region', 'slug'] and i = 1:
|
|
// - j=0: Add 'lang' parameter
|
|
// - j=1: Add 'region' parameter
|
|
// Result: { lang: 'en', region: 'US' }
|
|
for(let j = 0; j <= i; j++){
|
|
const routeKey = routeParamKeys[j];
|
|
// Check if the parameter exists in the original params object and has a defined value.
|
|
// This handles cases where generateStaticParams doesn't provide all possible parameters,
|
|
// or where some parameters are optional/undefined.
|
|
if (!params.hasOwnProperty(routeKey) || params[routeKey] === undefined) {
|
|
// If this missing parameter is a Root Parameter, mark the combination as invalid.
|
|
// Root Parameters are required for Static Shells, so we can't generate partial combinations without them.
|
|
if (rootParamKeys.includes(routeKey)) {
|
|
hasAllRootParams = false;
|
|
}
|
|
break;
|
|
}
|
|
const value = params[routeKey];
|
|
combination[routeKey] = value;
|
|
// Construct a unique key part for this parameter to enable deduplication.
|
|
// We use type prefixes to prevent collisions between different value types
|
|
// that might have the same string representation.
|
|
//
|
|
// Examples:
|
|
// - Array ['foo', 'bar'] becomes "A:foo,bar"
|
|
// - String "foo,bar" becomes "S:foo,bar"
|
|
// - This prevents collisions between ['foo', 'bar'] and "foo,bar"
|
|
let valuePart;
|
|
if (Array.isArray(value)) {
|
|
valuePart = `A:${value.join(',')}`;
|
|
} else {
|
|
valuePart = `S:${value}`;
|
|
}
|
|
keyParts.push(`${routeKey}:${valuePart}`);
|
|
}
|
|
// Build the final unique key by joining all parameter parts.
|
|
// This key is used for deduplication in the combinations Map.
|
|
// Format: "lang:S:en|region:S:US|slug:A:home,about"
|
|
const currentKey = keyParts.join('|');
|
|
// Only add the combination if it meets our criteria:
|
|
// 1. hasAllRootParams: Contains all required Root Parameters
|
|
// 2. !combinations.has(currentKey): Is not a duplicate of an existing combination
|
|
//
|
|
// This ensures we only generate valid, unique parameter combinations for Static Shells.
|
|
if (hasAllRootParams && !combinations.has(currentKey)) {
|
|
combinations.set(currentKey, combination);
|
|
}
|
|
}
|
|
}
|
|
// Convert the Map's values back into an array and return the final result.
|
|
// The Map ensures all combinations are unique, and we return only the
|
|
// parameter objects themselves, discarding the internal deduplication keys.
|
|
return Array.from(combinations.values());
|
|
}
|
|
function calculateFallbackMode(dynamicParams, fallbackRootParams, baseFallbackMode) {
|
|
return dynamicParams ? // perform a blocking static render.
|
|
fallbackRootParams.length > 0 ? _fallback.FallbackMode.BLOCKING_STATIC_RENDER : baseFallbackMode ?? _fallback.FallbackMode.NOT_FOUND : _fallback.FallbackMode.NOT_FOUND;
|
|
}
|
|
/**
|
|
* Validates the parameters to ensure they're accessible and have the correct
|
|
* types.
|
|
*
|
|
* @param page - The page to validate.
|
|
* @param regex - The route regex.
|
|
* @param isRoutePPREnabled - Whether the route has partial prerendering enabled.
|
|
* @param routeParamKeys - The keys of the parameters.
|
|
* @param rootParamKeys - The keys of the root params.
|
|
* @param routeParams - The list of parameters to validate.
|
|
* @returns The list of validated parameters.
|
|
*/ function validateParams(page, regex, isRoutePPREnabled, routeParamKeys, rootParamKeys, routeParams) {
|
|
const valid = [];
|
|
// Validate that if there are any root params, that the user has provided at
|
|
// least one value for them only if we're using partial prerendering.
|
|
if (isRoutePPREnabled && rootParamKeys.length > 0) {
|
|
if (routeParams.length === 0 || rootParamKeys.some((key)=>routeParams.some((params)=>!(key in params)))) {
|
|
if (rootParamKeys.length === 1) {
|
|
throw Object.defineProperty(new Error(`A required root parameter (${rootParamKeys[0]}) was not provided in generateStaticParams for ${page}, please provide at least one value.`), "__NEXT_ERROR_CODE", {
|
|
value: "E622",
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
}
|
|
throw Object.defineProperty(new Error(`Required root params (${rootParamKeys.join(', ')}) were not provided in generateStaticParams for ${page}, please provide at least one value for each.`), "__NEXT_ERROR_CODE", {
|
|
value: "E621",
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
}
|
|
}
|
|
for (const params of routeParams){
|
|
const item = {};
|
|
for (const key of routeParamKeys){
|
|
const { repeat, optional } = regex.groups[key];
|
|
let paramValue = params[key];
|
|
if (optional && params.hasOwnProperty(key) && (paramValue === null || paramValue === undefined || paramValue === false)) {
|
|
paramValue = [];
|
|
}
|
|
// A parameter is missing, so the rest of the params are not accessible.
|
|
// We only support this when the route has partial prerendering enabled.
|
|
// This will make it so that the remaining params are marked as missing so
|
|
// we can generate a fallback route for them.
|
|
if (!paramValue && isRoutePPREnabled) {
|
|
break;
|
|
}
|
|
// Perform validation for the parameter based on whether it's a repeat
|
|
// parameter or not.
|
|
if (repeat) {
|
|
if (!Array.isArray(paramValue)) {
|
|
throw Object.defineProperty(new Error(`A required parameter (${key}) was not provided as an array received ${typeof paramValue} in generateStaticParams for ${page}`), "__NEXT_ERROR_CODE", {
|
|
value: "E618",
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
}
|
|
} else {
|
|
if (typeof paramValue !== 'string') {
|
|
throw Object.defineProperty(new Error(`A required parameter (${key}) was not provided as a string received ${typeof paramValue} in generateStaticParams for ${page}`), "__NEXT_ERROR_CODE", {
|
|
value: "E617",
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
}
|
|
}
|
|
item[key] = paramValue;
|
|
}
|
|
valid.push(item);
|
|
}
|
|
return valid;
|
|
}
|
|
function assignErrorIfEmpty(prerenderedRoutes, routeParamKeys) {
|
|
// If there are no routes to process, exit early.
|
|
if (prerenderedRoutes.length === 0) {
|
|
return;
|
|
}
|
|
// Initialize the root of the Trie. This node represents the starting point
|
|
// before any parameters have been considered.
|
|
const root = {
|
|
children: new Map(),
|
|
routes: []
|
|
};
|
|
// Phase 1: Build the Trie.
|
|
// Iterate over each prerendered route and insert it into the Trie.
|
|
// Each route's concrete parameter values form a path in the Trie.
|
|
for (const route of prerenderedRoutes){
|
|
let currentNode = root // Start building the path from the root for each route.
|
|
;
|
|
// Iterate through the sorted parameter keys. The order of keys is crucial
|
|
// for ensuring that routes with the same concrete parameters follow the
|
|
// same path in the Trie, regardless of the original order of properties
|
|
// in the `params` object.
|
|
for (const key of routeParamKeys){
|
|
// Check if the current route actually has a concrete value for this parameter.
|
|
// If a dynamic segment is not filled (i.e., it's a fallback), it won't have
|
|
// this property, and we stop building the path for this route at this point.
|
|
if (route.params.hasOwnProperty(key)) {
|
|
const value = route.params[key];
|
|
// Generate a unique key for the parameter's value. This is critical
|
|
// to prevent collisions between different data types that might have
|
|
// the same string representation (e.g., `['a', 'b']` vs `'a,b'`).
|
|
// A type prefix (`A:` for Array, `S:` for String, `U:` for undefined)
|
|
// is added to the value to prevent collisions. This ensures that
|
|
// different types with the same string representation are treated as
|
|
// distinct.
|
|
let valueKey;
|
|
if (Array.isArray(value)) {
|
|
valueKey = `A:${value.join(',')}`;
|
|
} else if (value === undefined) {
|
|
valueKey = `U:undefined`;
|
|
} else {
|
|
valueKey = `S:${value}`;
|
|
}
|
|
// Look for a child node corresponding to this `valueKey` from the `currentNode`.
|
|
let childNode = currentNode.children.get(valueKey);
|
|
if (!childNode) {
|
|
// If the child node doesn't exist, create a new one and add it to
|
|
// the current node's children.
|
|
childNode = {
|
|
children: new Map(),
|
|
routes: []
|
|
};
|
|
currentNode.children.set(valueKey, childNode);
|
|
}
|
|
// Move deeper into the Trie to the `childNode` for the next parameter.
|
|
currentNode = childNode;
|
|
}
|
|
}
|
|
// After processing all concrete parameters for the route, add the full
|
|
// `PrerenderedRoute` object to the `routes` array of the `currentNode`.
|
|
// This node represents the unique concrete parameter combination for this route.
|
|
currentNode.routes.push(route);
|
|
}
|
|
// Phase 2: Traverse the Trie to assign the `throwOnEmptyStaticShell` property.
|
|
// This is done using an iterative Depth-First Search (DFS) approach with an
|
|
// explicit stack to avoid JavaScript's recursion depth limits (stack overflow)
|
|
// for very deep routing structures.
|
|
const stack = [
|
|
root
|
|
] // Initialize the stack with the root node.
|
|
;
|
|
while(stack.length > 0){
|
|
const node = stack.pop()// Pop the next node to process from the stack.
|
|
;
|
|
// `hasChildren` indicates if this node has any more specific concrete
|
|
// parameter combinations branching off from it. If true, it means this
|
|
// node represents a prefix for other, more specific routes.
|
|
const hasChildren = node.children.size > 0;
|
|
// If the current node has routes associated with it (meaning, routes whose
|
|
// concrete parameters lead to this node's path in the Trie).
|
|
if (node.routes.length > 0) {
|
|
// Determine the minimum number of fallback parameters among all routes
|
|
// that are associated with this current Trie node. This is used to
|
|
// identify if a route should not throw on empty static shell relative to another route *at the same level*
|
|
// of concrete parameters, but with fewer fallback parameters.
|
|
let minFallbacks = Infinity;
|
|
for (const r of node.routes){
|
|
var _r_fallbackRouteParams;
|
|
// `fallbackRouteParams?.length ?? 0` handles cases where `fallbackRouteParams`
|
|
// might be `undefined` or `null`, treating them as 0 length.
|
|
minFallbacks = Math.min(minFallbacks, ((_r_fallbackRouteParams = r.fallbackRouteParams) == null ? void 0 : _r_fallbackRouteParams.length) ?? 0);
|
|
}
|
|
// Now, for each `PrerenderedRoute` associated with this node:
|
|
for (const route of node.routes){
|
|
// A route is ok not to throw on an empty static shell (and thus
|
|
// `throwOnEmptyStaticShell` should be `false`) if either of the
|
|
// following conditions is met:
|
|
// 1. `hasChildren` is true: This node has further concrete parameter children.
|
|
// This means the current route is a parent to more specific routes (e.g.,
|
|
// `/blog/[slug]` should not throw when concrete routes like `/blog/first-post` exist).
|
|
// OR
|
|
// 2. `route.fallbackRouteParams.length > minFallbacks`: This route has
|
|
// more fallback parameters than another route at the same Trie node.
|
|
// This implies the current route is a more general version that should not throw
|
|
// compared to a more specific route that has fewer fallback parameters
|
|
// (e.g., `/1234/[...slug]` should not throw relative to `/[id]/[...slug]`).
|
|
if (hasChildren || route.fallbackRouteParams && route.fallbackRouteParams.length > minFallbacks) {
|
|
route.throwOnEmptyStaticShell = false // Should not throw on empty static shell.
|
|
;
|
|
} else {
|
|
route.throwOnEmptyStaticShell = true // Should throw on empty static shell.
|
|
;
|
|
}
|
|
}
|
|
}
|
|
// Add all children of the current node to the stack. This ensures that
|
|
// the traversal continues to explore deeper paths in the Trie.
|
|
for (const child of node.children.values()){
|
|
stack.push(child);
|
|
}
|
|
}
|
|
}
|
|
async function generateRouteStaticParams(segments, store) {
|
|
// Early return if no segments to process
|
|
if (segments.length === 0) return [];
|
|
const queue = [
|
|
{
|
|
segmentIndex: 0,
|
|
params: []
|
|
}
|
|
];
|
|
let currentParams = [];
|
|
while(queue.length > 0){
|
|
var _current_config;
|
|
const { segmentIndex, params } = queue.shift();
|
|
// If we've processed all segments, this is our final result
|
|
if (segmentIndex >= segments.length) {
|
|
currentParams = params;
|
|
break;
|
|
}
|
|
const current = segments[segmentIndex];
|
|
// Skip segments without generateStaticParams and continue to next
|
|
if (typeof current.generateStaticParams !== 'function') {
|
|
queue.push({
|
|
segmentIndex: segmentIndex + 1,
|
|
params
|
|
});
|
|
continue;
|
|
}
|
|
// Configure fetchCache if specified
|
|
if (((_current_config = current.config) == null ? void 0 : _current_config.fetchCache) !== undefined) {
|
|
store.fetchCache = current.config.fetchCache;
|
|
}
|
|
const nextParams = [];
|
|
// If there are parent params, we need to process them.
|
|
if (params.length > 0) {
|
|
// Process each parent parameter combination
|
|
for (const parentParams of params){
|
|
const result = await current.generateStaticParams({
|
|
params: parentParams
|
|
});
|
|
if (result.length > 0) {
|
|
// Merge parent params with each result item
|
|
for (const item of result){
|
|
nextParams.push({
|
|
...parentParams,
|
|
...item
|
|
});
|
|
}
|
|
} else {
|
|
// No results, just pass through parent params
|
|
nextParams.push(parentParams);
|
|
}
|
|
}
|
|
} else {
|
|
// No parent params, call generateStaticParams with empty object
|
|
const result = await current.generateStaticParams({
|
|
params: {}
|
|
});
|
|
nextParams.push(...result);
|
|
}
|
|
// Add next segment to work queue
|
|
queue.push({
|
|
segmentIndex: segmentIndex + 1,
|
|
params: nextParams
|
|
});
|
|
}
|
|
return currentParams;
|
|
}
|
|
async function buildAppStaticPaths({ dir, page, distDir, cacheComponents, authInterrupts, segments, isrFlushToDisk, cacheHandler, cacheLifeProfiles, requestHeaders, cacheHandlers, maxMemoryCacheSize, fetchCacheKeyPrefix, nextConfigOutput, ComponentMod, isRoutePPREnabled = false, buildId, rootParamKeys }) {
|
|
if (segments.some((generate)=>{
|
|
var _generate_config;
|
|
return ((_generate_config = generate.config) == null ? void 0 : _generate_config.dynamicParams) === true;
|
|
}) && nextConfigOutput === 'export') {
|
|
throw Object.defineProperty(new Error('"dynamicParams: true" cannot be used with "output: export". See more info here: https://nextjs.org/docs/app/building-your-application/deploying/static-exports'), "__NEXT_ERROR_CODE", {
|
|
value: "E393",
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
}
|
|
ComponentMod.patchFetch();
|
|
const incrementalCache = await (0, _createincrementalcache.createIncrementalCache)({
|
|
dir,
|
|
distDir,
|
|
cacheHandler,
|
|
cacheHandlers,
|
|
requestHeaders,
|
|
fetchCacheKeyPrefix,
|
|
flushToDisk: isrFlushToDisk,
|
|
cacheMaxMemorySize: maxMemoryCacheSize
|
|
});
|
|
const regex = (0, _routeregex.getRouteRegex)(page);
|
|
const routeParamKeys = Object.keys((0, _routematcher.getRouteMatcher)(regex)(page) || {});
|
|
const afterRunner = new _runwithafter.AfterRunner();
|
|
const store = (0, _workstore.createWorkStore)({
|
|
page,
|
|
renderOpts: {
|
|
incrementalCache,
|
|
cacheLifeProfiles,
|
|
supportsDynamicResponse: true,
|
|
isRevalidate: false,
|
|
experimental: {
|
|
cacheComponents,
|
|
authInterrupts
|
|
},
|
|
waitUntil: afterRunner.context.waitUntil,
|
|
onClose: afterRunner.context.onClose,
|
|
onAfterTaskError: afterRunner.context.onTaskError
|
|
},
|
|
buildId,
|
|
previouslyRevalidatedTags: []
|
|
});
|
|
const routeParams = await ComponentMod.workAsyncStorage.run(store, ()=>generateRouteStaticParams(segments, store));
|
|
await afterRunner.executeAfter();
|
|
let lastDynamicSegmentHadGenerateStaticParams = false;
|
|
for (const segment of segments){
|
|
var _segment_config;
|
|
// Check to see if there are any missing params for segments that have
|
|
// dynamicParams set to false.
|
|
if (segment.param && segment.isDynamicSegment && ((_segment_config = segment.config) == null ? void 0 : _segment_config.dynamicParams) === false) {
|
|
for (const params of routeParams){
|
|
if (segment.param in params) continue;
|
|
const relative = segment.filePath ? _nodepath.default.relative(dir, segment.filePath) : undefined;
|
|
throw Object.defineProperty(new Error(`Segment "${relative}" exports "dynamicParams: false" but the param "${segment.param}" is missing from the generated route params.`), "__NEXT_ERROR_CODE", {
|
|
value: "E280",
|
|
enumerable: false,
|
|
configurable: true
|
|
});
|
|
}
|
|
}
|
|
if (segment.isDynamicSegment && typeof segment.generateStaticParams !== 'function') {
|
|
lastDynamicSegmentHadGenerateStaticParams = false;
|
|
} else if (typeof segment.generateStaticParams === 'function') {
|
|
lastDynamicSegmentHadGenerateStaticParams = true;
|
|
}
|
|
}
|
|
// Determine if all the segments have had their parameters provided.
|
|
const hadAllParamsGenerated = routeParamKeys.length === 0 || routeParams.length > 0 && routeParams.every((params)=>{
|
|
for (const key of routeParamKeys){
|
|
if (key in params) continue;
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
// TODO: dynamic params should be allowed to be granular per segment but
|
|
// we need additional information stored/leveraged in the prerender
|
|
// manifest to allow this behavior.
|
|
const dynamicParams = segments.every((segment)=>{
|
|
var _segment_config;
|
|
return ((_segment_config = segment.config) == null ? void 0 : _segment_config.dynamicParams) !== false;
|
|
});
|
|
const supportsRoutePreGeneration = hadAllParamsGenerated || process.env.NODE_ENV === 'production';
|
|
const fallbackMode = dynamicParams ? supportsRoutePreGeneration ? isRoutePPREnabled ? _fallback.FallbackMode.PRERENDER : _fallback.FallbackMode.BLOCKING_STATIC_RENDER : undefined : _fallback.FallbackMode.NOT_FOUND;
|
|
const prerenderedRoutesByPathname = new Map();
|
|
// Precompile the regex patterns for the route params.
|
|
const paramPatterns = new Map();
|
|
for (const key of routeParamKeys){
|
|
const { repeat, optional } = regex.groups[key];
|
|
let pattern = `[${repeat ? '...' : ''}${key}]`;
|
|
if (optional) {
|
|
pattern = `[${pattern}]`;
|
|
}
|
|
paramPatterns.set(key, pattern);
|
|
}
|
|
// Convert rootParamKeys to Set for O(1) lookup.
|
|
const rootParamSet = new Set(rootParamKeys);
|
|
if (hadAllParamsGenerated || isRoutePPREnabled) {
|
|
let paramsToProcess = routeParams;
|
|
if (isRoutePPREnabled) {
|
|
// Discover all unique combinations of the routeParams so we can generate
|
|
// routes that won't throw on empty static shell for each of them if
|
|
// they're available.
|
|
paramsToProcess = generateAllParamCombinations(routeParamKeys, routeParams, rootParamKeys);
|
|
// Add the base route, this is the route with all the placeholders as it's
|
|
// derived from the `page` string.
|
|
prerenderedRoutesByPathname.set(page, {
|
|
params: {},
|
|
pathname: page,
|
|
encodedPathname: page,
|
|
fallbackRouteParams: routeParamKeys,
|
|
fallbackMode: calculateFallbackMode(dynamicParams, rootParamKeys, fallbackMode),
|
|
fallbackRootParams: rootParamKeys,
|
|
throwOnEmptyStaticShell: true
|
|
});
|
|
}
|
|
filterUniqueParams(routeParamKeys, validateParams(page, regex, isRoutePPREnabled, routeParamKeys, rootParamKeys, paramsToProcess)).forEach((params)=>{
|
|
let pathname = page;
|
|
let encodedPathname = page;
|
|
const fallbackRouteParams = [];
|
|
for (const key of routeParamKeys){
|
|
const paramValue = params[key];
|
|
if (!paramValue) {
|
|
if (isRoutePPREnabled) {
|
|
// Mark remaining params as fallback params.
|
|
fallbackRouteParams.push(key);
|
|
for(let i = routeParamKeys.indexOf(key) + 1; i < routeParamKeys.length; i++){
|
|
fallbackRouteParams.push(routeParamKeys[i]);
|
|
}
|
|
break;
|
|
} else {
|
|
// This route is not complete, and we aren't performing a partial
|
|
// prerender, so we should return, skipping this route.
|
|
return;
|
|
}
|
|
}
|
|
// Use pre-compiled pattern for replacement
|
|
const pattern = paramPatterns.get(key);
|
|
pathname = pathname.replace(pattern, (0, _utils.encodeParam)(paramValue, (value)=>(0, _escapepathdelimiters.default)(value, true)));
|
|
encodedPathname = encodedPathname.replace(pattern, (0, _utils.encodeParam)(paramValue, encodeURIComponent));
|
|
}
|
|
const fallbackRootParams = [];
|
|
for (const param of fallbackRouteParams){
|
|
if (rootParamSet.has(param)) {
|
|
fallbackRootParams.push(param);
|
|
}
|
|
}
|
|
pathname = (0, _utils.normalizePathname)(pathname);
|
|
prerenderedRoutesByPathname.set(pathname, {
|
|
params,
|
|
pathname,
|
|
encodedPathname: (0, _utils.normalizePathname)(encodedPathname),
|
|
fallbackRouteParams,
|
|
fallbackMode: calculateFallbackMode(dynamicParams, fallbackRootParams, fallbackMode),
|
|
fallbackRootParams,
|
|
throwOnEmptyStaticShell: true
|
|
});
|
|
});
|
|
}
|
|
const prerenderedRoutes = prerenderedRoutesByPathname.size > 0 || lastDynamicSegmentHadGenerateStaticParams ? [
|
|
...prerenderedRoutesByPathname.values()
|
|
] : undefined;
|
|
// Now we have to set the throwOnEmptyStaticShell for each of the routes.
|
|
if (prerenderedRoutes && cacheComponents) {
|
|
assignErrorIfEmpty(prerenderedRoutes, routeParamKeys);
|
|
}
|
|
return {
|
|
fallbackMode,
|
|
prerenderedRoutes
|
|
};
|
|
}
|
|
|
|
//# sourceMappingURL=app.js.map
|