Skip to content

@angular/ssr: getPrerenderParams silently skipped due to stateful /g regex in URL_PARAMETER_REGEXP #33154

@SvenBudak

Description

@SvenBudak

Which @angular/* package(s) are the source of the bug?

@angular/ssr

Is this a regression?

No

Description

When multiple parameterized routes use RenderMode.Prerender with getPrerenderParams, some routes are silently skipped — getPrerenderParams is never called, no prerendered HTML is produced, and no warning is emitted. The build reports "Prerendered N static routes" with N lower than expected.

Root cause

In @angular/ssr/fesm2022/ssr.mjs, function handleSSGRoute:

const URL_PARAMETER_REGEXP = /(?<!\\):([^/]+)/g;  // <-- /g flag

if (isCatchAllRoute && !getPrerenderParams ||
    !isCatchAllRoute && !URL_PARAMETER_REGEXP.test(currentRoutePath)) {
  yield { ...meta };  // early return, getPrerenderParams never called
  return;
}

The /g flag makes RegExp.prototype.test() stateful — lastIndex persists across calls. After a successful match, the next .test() call starts mid-string and may return false for a path that does contain a parameter. The route is then treated as static and yielded without invoking getPrerenderParams.

Standalone reproduction (no Angular needed)

const URL_PARAMETER_REGEXP = /(?<!\\):([^/]+)/g;
console.log(URL_PARAMETER_REGEXP.test('blog/:slug'));            // true
console.log(URL_PARAMETER_REGEXP.test('blog/kategorie/:cat'));   // false  ← BUG

Suggested fix

Drop the /g flag (not needed for .test()), or reset lastIndex before each test:

   const isCatchAllRoute = CATCH_ALL_REGEXP.test(currentRoutePath);
+  URL_PARAMETER_REGEXP.lastIndex = 0;
   if (isCatchAllRoute && !getPrerenderParams || !isCatchAllRoute && !URL_PARAMETER_REGEXP.test(currentRoutePath)) {

Please provide a link to a minimal reproduction of the bug

No response

Please provide the exception or error you saw

No exception. The bug is silent: getPrerenderParams is not invoked for affected routes, and the build log reports a lower count of prerendered routes than expected without any warning.

Please provide the environment you discovered this bug in (run ng version)

Angular           : 21.2.4
Node.js           : 22.14.0
Package Manager   : pnpm 10.6.5
Operating System  : win32 x64

Package                     Installed Version  Requested Version
@angular/build              21.2.2             ^21.2.2
@angular/cdk                21.2.2             ^21.2.2
@angular/cli                21.2.2             ^21.2.2
@angular/common             21.2.4             ^21.2.0
@angular/compiler           21.2.4             ^21.2.0
@angular/compiler-cli       21.2.4             ^21.2.0
@angular/core               21.2.4             ^21.2.0
@angular/forms              21.2.4             ^21.2.0
@angular/material           21.2.2             ^21.2.2
@angular/platform-browser   21.2.4             ^21.2.0
@angular/platform-server    21.2.4             ^21.2.0
@angular/router             21.2.4             ^21.2.0
@angular/ssr                21.2.2             ^21.2.2
rxjs                        7.8.2              ~7.8.0
typescript                  5.9.3              ~5.9.2

Anything else?

Also reproduced with @angular/ssr 21.2.10 and 22.0.0-next.7 by patching the file in node_modules and rerunning the build — the same routes are skipped without the lastIndex = 0 fix.

Currently working around this via pnpm patch:

   const isCatchAllRoute = CATCH_ALL_REGEXP.test(currentRoutePath);
+  URL_PARAMETER_REGEXP.lastIndex = 0;
   if (isCatchAllRoute && !getPrerenderParams || !isCatchAllRoute && !URL_PARAMETER_REGEXP.test(currentRoutePath)) {

Before patch: 7 of 11 expected parameterized routes were prerendered.
After patch: all 20 routes correctly prerendered.

Happy to submit a PR if helpful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions