@@ -818,6 +818,11 @@ class RouteTree {
818
818
* initial scripts.
819
819
*/
820
820
const MODULE_PRELOAD_MAX = 10 ;
821
+ /**
822
+ * Regular expression to match a catch-all route pattern in a URL path,
823
+ * specifically one that ends with '/**'.
824
+ */
825
+ const CATCH_ALL_REGEXP = / \/ ( \* \* ) $ / ;
821
826
/**
822
827
* Regular expression to match segments preceded by a colon in a string.
823
828
*/
@@ -1024,7 +1029,9 @@ async function* handleSSGRoute(serverConfigRouteTree, redirectTo, metadata, pare
1024
1029
if ( redirectTo !== undefined ) {
1025
1030
meta . redirectTo = resolveRedirectTo ( currentRoutePath , redirectTo ) ;
1026
1031
}
1027
- if ( ! URL_PARAMETER_REGEXP . test ( currentRoutePath ) ) {
1032
+ const isCatchAllRoute = CATCH_ALL_REGEXP . test ( currentRoutePath ) ;
1033
+ if ( ( isCatchAllRoute && ! getPrerenderParams ) ||
1034
+ ( ! isCatchAllRoute && ! URL_PARAMETER_REGEXP . test ( currentRoutePath ) ) ) {
1028
1035
// Route has no parameters
1029
1036
yield {
1030
1037
...meta ,
@@ -1043,7 +1050,9 @@ async function* handleSSGRoute(serverConfigRouteTree, redirectTo, metadata, pare
1043
1050
}
1044
1051
if ( serverConfigRouteTree ) {
1045
1052
// Automatically resolve dynamic parameters for nested routes.
1046
- const catchAllRoutePath = joinUrlParts ( currentRoutePath , '**' ) ;
1053
+ const catchAllRoutePath = isCatchAllRoute
1054
+ ? currentRoutePath
1055
+ : joinUrlParts ( currentRoutePath , '**' ) ;
1047
1056
const match = serverConfigRouteTree . match ( catchAllRoutePath ) ;
1048
1057
if ( match && match . renderMode === RenderMode . Prerender && ! ( 'getPrerenderParams' in match ) ) {
1049
1058
serverConfigRouteTree . insert ( catchAllRoutePath , {
@@ -1056,17 +1065,10 @@ async function* handleSSGRoute(serverConfigRouteTree, redirectTo, metadata, pare
1056
1065
const parameters = await runInInjectionContext ( parentInjector , ( ) => getPrerenderParams ( ) ) ;
1057
1066
try {
1058
1067
for ( const params of parameters ) {
1059
- const routeWithResolvedParams = currentRoutePath . replace ( URL_PARAMETER_REGEXP , ( match ) => {
1060
- const parameterName = match . slice ( 1 ) ;
1061
- const value = params [ parameterName ] ;
1062
- if ( typeof value !== 'string' ) {
1063
- throw new Error ( `The 'getPrerenderParams' function defined for the '${ stripLeadingSlash ( currentRoutePath ) } ' route ` +
1064
- `returned a non-string value for parameter '${ parameterName } '. ` +
1065
- `Please make sure the 'getPrerenderParams' function returns values for all parameters ` +
1066
- 'specified in this route.' ) ;
1067
- }
1068
- return value ;
1069
- } ) ;
1068
+ const replacer = handlePrerenderParamsReplacement ( params , currentRoutePath ) ;
1069
+ const routeWithResolvedParams = currentRoutePath
1070
+ . replace ( URL_PARAMETER_REGEXP , replacer )
1071
+ . replace ( CATCH_ALL_REGEXP , replacer ) ;
1070
1072
yield {
1071
1073
...meta ,
1072
1074
route : routeWithResolvedParams ,
@@ -1091,6 +1093,27 @@ async function* handleSSGRoute(serverConfigRouteTree, redirectTo, metadata, pare
1091
1093
} ;
1092
1094
}
1093
1095
}
1096
+ /**
1097
+ * Creates a replacer function used for substituting parameter placeholders in a route path
1098
+ * with their corresponding values provided in the `params` object.
1099
+ *
1100
+ * @param params - An object mapping parameter names to their string values.
1101
+ * @param currentRoutePath - The current route path, used for constructing error messages.
1102
+ * @returns A function that replaces a matched parameter placeholder (e.g., ':id') with its corresponding value.
1103
+ */
1104
+ function handlePrerenderParamsReplacement ( params , currentRoutePath ) {
1105
+ return ( match ) => {
1106
+ const parameterName = match . slice ( 1 ) ;
1107
+ const value = params [ parameterName ] ;
1108
+ if ( typeof value !== 'string' ) {
1109
+ throw new Error ( `The 'getPrerenderParams' function defined for the '${ stripLeadingSlash ( currentRoutePath ) } ' route ` +
1110
+ `returned a non-string value for parameter '${ parameterName } '. ` +
1111
+ `Please make sure the 'getPrerenderParams' function returns values for all parameters ` +
1112
+ 'specified in this route.' ) ;
1113
+ }
1114
+ return parameterName === '**' ? `/${ value } ` : value ;
1115
+ } ;
1116
+ }
1094
1117
/**
1095
1118
* Resolves the `redirectTo` property for a given route.
1096
1119
*
@@ -1138,8 +1161,8 @@ function buildServerConfigRouteTree({ routes, appShellRoute }) {
1138
1161
errors . push ( `Invalid '${ path } ' route configuration: the path cannot start with a slash.` ) ;
1139
1162
continue ;
1140
1163
}
1141
- if ( path . includes ( '* ' ) && 'getPrerenderParams' in metadata ) {
1142
- errors . push ( `Invalid '${ path } ' route configuration: 'getPrerenderParams' cannot be used with a '*' or '**' route.` ) ;
1164
+ if ( 'getPrerenderParams' in metadata && ( path . includes ( '/*/ ' ) || path . endsWith ( '/*' ) ) ) {
1165
+ errors . push ( `Invalid '${ path } ' route configuration: 'getPrerenderParams' cannot be used with a '*' route.` ) ;
1143
1166
continue ;
1144
1167
}
1145
1168
serverConfigRouteTree . insert ( path , metadata ) ;
0 commit comments