-
Notifications
You must be signed in to change notification settings - Fork 11.9k
Description
Command
build
Description
When building an SSR app with outputMode: 'server', Angular runs a "route extraction" phase to discover all routes for the manifest. The problem is this phase bootstraps our app and runs all APP_INITIALIZERs - including ones that make HTTP calls, etc. which we don't want to run during the build but only during and actual live SSR or actual Prerendering.
These initializers make sense during:
- Live SSR (handling actual user requests)
- Prerendering (generating static HTML at build time) - if only we want to do the prerendering (which is not always the case when running the build!)
But during the build (and route extraction), we don't need (or want) to hit our APIs.
Side note: The route extraction phase is executed, even when serverRoutes have no route with Prerender mode.
What we tried:
We dug into the internals and found that ɵSERVER_CONTEXT from @angular/platform-server is the only way to tell these phases apart:
- Route extraction:
null - Prerendering:
'ssg' - Live SSR:
'ssr'
But since it's a private API (the ɵ prefix), we can't rely on it. We're building an open-source Angular meta-framework for creating ecommerce sites. If we used Angular private API and Angular suddenly changes the private API anytime, we don't want our framework to break for our customers.
We also considered the public tokens REQUEST, RESPONSE_INIT and REQUEST_CONTEXT, but they are all null in both route extraction AND prerendering, so they can't help us distinguish between the two, in case we'd like to run an actual prerendering sometimes.
Describe the solution you'd like
Option A: Let us detect the context
Expose a public token like SERVER_RENDER_CONTEXT (or make ɵSERVER_CONTEXT public) with values like:
'route-extraction'- build-time route discovery'ssg'- prerendering'ssr'- live server rendering
Then we could do:
provideAppInitializer(() => {
const context = inject(SERVER_RENDER_CONTEXT, { optional: true });
if (context === 'route-extraction') {
return; // Skip
}
// Do the work for actual SSG/SSR
})Option B: Skip APP_INITIALIZERs during route extraction
Have Angular skip running APP_INITIALIZERs entirely during route extraction, since:
- Route extraction only needs the Router config
- It already sets
_ENABLE_ROOT_COMPONENT_BOOTSTRAP: falseinternally - Not running initializers would be consistent with that "lightweight" approach
Though it might be risky - some apps might have APP_INITIALIZERS that configure routes dynamically.
Describe alternatives you've considered
-
Using
ɵSERVER_CONTEXT- Works but it's private API, can't use it in a our meta-framework we distribute -
Checking
REQUESTtoken - Both route extraction and prerendering haveREQUEST: null, so no way to tell them apart 🙁