@@ -21,7 +21,7 @@ import { ServerAssets } from '../assets';
2121import { Console } from '../console' ;
2222import { AngularAppManifest , getAngularAppManifest } from '../manifest' ;
2323import { AngularBootstrap , isNgModule } from '../utils/ng' ;
24- import { joinUrlParts , stripLeadingSlash } from '../utils/url' ;
24+ import { addTrailingSlash , joinUrlParts , stripLeadingSlash } from '../utils/url' ;
2525import {
2626 PrerenderFallback ,
2727 RenderMode ,
@@ -146,31 +146,36 @@ async function* traverseRoutesConfig(options: {
146146 const metadata : ServerConfigRouteTreeNodeMetadata = {
147147 renderMode : RenderMode . Prerender ,
148148 ...matchedMetaData ,
149- route : currentRoutePath ,
149+ // Match Angular router behavior
150+ // ['one', 'two', ''] -> 'one/two/'
151+ // ['one', 'two', 'three'] -> 'one/two/three'
152+ route : path === '' ? addTrailingSlash ( currentRoutePath ) : currentRoutePath ,
150153 } ;
151154
152155 delete metadata . presentInClientRouter ;
153156
154- // Handle redirects
155- if ( typeof redirectTo === 'string' ) {
156- const redirectToResolved = resolveRedirectTo ( currentRoutePath , redirectTo ) ;
157+ if ( metadata . renderMode === RenderMode . Prerender ) {
158+ // Handle SSG routes
159+ yield * handleSSGRoute (
160+ typeof redirectTo === 'string' ? redirectTo : undefined ,
161+ metadata ,
162+ parentInjector ,
163+ invokeGetPrerenderParams ,
164+ includePrerenderFallbackRoutes ,
165+ ) ;
166+ } else if ( typeof redirectTo === 'string' ) {
167+ // Handle redirects
157168 if ( metadata . status && ! VALID_REDIRECT_RESPONSE_CODES . has ( metadata . status ) ) {
158169 yield {
159170 error :
160171 `The '${ metadata . status } ' status code is not a valid redirect response code. ` +
161172 `Please use one of the following redirect response codes: ${ [ ...VALID_REDIRECT_RESPONSE_CODES . values ( ) ] . join ( ', ' ) } .` ,
162173 } ;
174+
163175 continue ;
164176 }
165- yield { ...metadata , redirectTo : redirectToResolved } ;
166- } else if ( metadata . renderMode === RenderMode . Prerender ) {
167- // Handle SSG routes
168- yield * handleSSGRoute (
169- metadata ,
170- parentInjector ,
171- invokeGetPrerenderParams ,
172- includePrerenderFallbackRoutes ,
173- ) ;
177+
178+ yield { ...metadata , redirectTo : resolveRedirectTo ( metadata . route , redirectTo ) } ;
174179 } else {
175180 yield metadata ;
176181 }
@@ -214,13 +219,15 @@ async function* traverseRoutesConfig(options: {
214219 * Handles SSG (Static Site Generation) routes by invoking `getPrerenderParams` and yielding
215220 * all parameterized paths, returning any errors encountered.
216221 *
222+ * @param redirectTo - Optional path to redirect to, if specified.
217223 * @param metadata - The metadata associated with the route tree node.
218224 * @param parentInjector - The dependency injection container for the parent route.
219225 * @param invokeGetPrerenderParams - A flag indicating whether to invoke the `getPrerenderParams` function.
220226 * @param includePrerenderFallbackRoutes - A flag indicating whether to include fallback routes in the result.
221227 * @returns An async iterable iterator that yields route tree node metadata for each SSG path or errors.
222228 */
223229async function * handleSSGRoute (
230+ redirectTo : string | undefined ,
224231 metadata : ServerConfigRouteTreeNodeMetadata ,
225232 parentInjector : Injector ,
226233 invokeGetPrerenderParams : boolean ,
@@ -239,6 +246,10 @@ async function* handleSSGRoute(
239246 delete meta [ 'getPrerenderParams' ] ;
240247 }
241248
249+ if ( redirectTo !== undefined ) {
250+ meta . redirectTo = resolveRedirectTo ( currentRoutePath , redirectTo ) ;
251+ }
252+
242253 if ( ! URL_PARAMETER_REGEXP . test ( currentRoutePath ) ) {
243254 // Route has no parameters
244255 yield {
@@ -279,7 +290,12 @@ async function* handleSSGRoute(
279290 return value ;
280291 } ) ;
281292
282- yield { ...meta , route : routeWithResolvedParams } ;
293+ const result = { ...meta , route : routeWithResolvedParams } ;
294+ if ( redirectTo !== undefined ) {
295+ result . redirectTo = resolveRedirectTo ( routeWithResolvedParams , redirectTo ) ;
296+ }
297+
298+ yield result ;
283299 }
284300 } catch ( error ) {
285301 yield { error : `${ ( error as Error ) . message } ` } ;
@@ -456,7 +472,6 @@ export async function getRoutesFromAngularRouterConfig(
456472 includePrerenderFallbackRoutes,
457473 } ) ;
458474
459- let seenAppShellRoute : string | undefined ;
460475 for await ( const result of traverseRoutes ) {
461476 if ( 'error' in result ) {
462477 errors . push ( result . error ) ;
0 commit comments