-
Notifications
You must be signed in to change notification settings - Fork 12k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Route extraction shouldnt load the whole app in dev server #29085
Comments
In this case, the REQUEST token being During route extraction, the application is bootstrapped to:
Bootstrapping enables key operations to be performed ahead of time:
By "bad practice," I meant that developers should avoid relying on the request being guaranteed in a server-side application during execution. Ensuring applications are future-proof and adaptable allows them to take advantage of upcoming features where a request might not always be available. This approach also provides flexibility to switch rendering modes in the future if needed. /cc @dgp1130 for additional input. |
Thank you very much for the detailed explanation.
Aren't these all things for which we don't actually need a component lifecycle? I would have thought that if you create routes dynamically, you would do this via a provider and not via components. As I said, I am not familiar with the angular internal code, but even for child routers it should somehow be possible to generate these routes AOT without doing a complete component lifecycle. I don't see any reason why components should create routes dynamically, do you? Or have internal things been built so that a refactor would be too big in relation to this bug? |
@alan-agius4 is definitely the expert here, so I don't think I have too much more to add. Like he mentioned, route extraction is useful to do at build time even if you don't have any Regardless, it feels like you want to write a component which requires a I think the only time it could hypothetically be safe to require a |
Just to add some more, currently when an application is bootstrapped using the While this behavior shouldn’t be strictly necessary, it is how Angular currently initializes an application. I’ve been exploring a potential solution to prevent the root component from being invoked during this process. I have a change in mind to do in the framework that should address this issue, but I still need to verify that it doesn’t introduce any unintended side effects or break other functionality. |
I have a (probably naive) question without knowing the internal code of angular: When angular is called with I just don't know how to handle this case in my app/library, because requests are made for the first page load, which must return a correct value, otherwise errors will occur. If it's just an app, I could just make a guard that blocks this "ghost" request, but in my case it's a library and you can't do that. If you are the expert on this topic, of course I respect your decision and you can close the ticket if you really think there is no way around it. I just think it's a bit sad because I really like angular and have liked all the decisions so far, except for this one :/ |
We don’t invoke the guards, or lifecycle hooks of all components, only those that are referenced in the AppComponent (root page). I am looking into a way to not do this.
I am not quite sure of your use-case, but especially in a library, I would say that it paramount not to assume the existing of a request, otherwise the library will not be compatible with other rendering modes including CSR or potentially you will end up using I am happy to provide more information, if you provide some more context on what you are trying to do in this library. |
My library actually works exactly like the http client (with hydration and csr). I would have the same problem with the http client. Imagine an empty angular app where an auth guard In prod it wouldn't be a problem, I understand that. But during development, a new user is created with every frontend change. This is just an example and I am aware that this behavior can be avoided with a dirty fix. I strongly believe that the more people upgrade now and use ssr in the dev server, they will have this same issue. |
However,
I'm not fully clear on the "create user" process. Are you creating a new user for every request that lacks a cookie? For instance, if I make 10,000 requests without a cookie, will 10,000 new users be created? This seems like a significant security risk unless your application is internal and not publicly accessible.
I agree, relying on // auth.service.ts
@Injectable()
export abstract class AuthService {
abstract isAuthenticated(): Promise<boolean>;
getUserId() { }
createUser() { }
// other common methods
}
// browser-auth.service.ts (Browser Implementation)
export class BrowserAuthService extends AuthService {
isAuthenticated(): boolean {
const token = document.cookie;
return !!token;
}
}
// server-auth.service.ts (Server Implementation)
export class ServerAuthService extends AuthService {
private readonly request: Response | null = inject(REQUEST);
isAuthenticated(): Observable<boolean> {
const token = this.request?.headers?.get('cookie');
return !!token;
}
}
// auth.guard.ts
export const authGuard: CanActivateFn = (route, state) => {
const authService = inject(AuthService);
const router = inject(Router);
const isAuthenticated = authService.isAuthenticated();
}; |
Something like Anonymous Sign-Ins like supabase does it are totally fine and are no security risk.
But it's not about the actual implementation. I just wanted to make a simple example to demonstrate what side effects a “ghost” bootstrap would have. Because of this unexpected behavior, there will be more and similar issues/questions like this: |
Thank you for the additional information. I am currently focusing on resolving the issue, rather than running the AppComponent. To clarify and correctness, while the issue described in https://stackoverflow.com/questions/79158723/angular-cookie-not-available-in-the-first-execution-of-app-initializer-function may seem similar, it is actually a very different problem. The root cause there is that the APIs used are tightly coupled with Express, which makes them non-portable and incompatible with the dev-server. |
Introduced the `DISABLE_COMPONENT_BOOTSTRAP` token to control the bootstrapping of components during application initialization. This token is utilized by the Angular CLI in the `@angular/ssr` package, particularly during server-side rendering (SSR) when extracting routes. When set to `true`, this token prevents the root component from being bootstrapped during SSR's route extraction phase, which is crucial for efficiently extracting routes without triggering component initialization. This mechanism separates the concerns of route extraction and component bootstrapping during SSR rendering, optimizing performance. If not provided or set to `false`, the default behavior of bootstrapping the root component(s) during initialization is maintained. Context: angular/angular-cli#29085
…ction This commit disables component bootstrapping during route extraction to prevent invoking the AppComponent and its lifecycle hooks. Closes angular#29085
…ction This commit disables component bootstrapping during route extraction to prevent invoking the AppComponent and its lifecycle hooks. Closes angular#29085
So you could theoretically disable component bootstrapping for route extraction in the dev server, but enable it again later during the actual build? That would be a really nice change |
Yes |
Introduced the `DISABLE_COMPONENT_BOOTSTRAP` token to control the bootstrapping of components during application initialization. This token is utilized by the Angular CLI in the `@angular/ssr` package, particularly during server-side rendering (SSR) when extracting routes. When set to `true`, this token prevents the root component from being bootstrapped during SSR's route extraction phase, which is crucial for efficiently extracting routes without triggering component initialization. This mechanism separates the concerns of route extraction and component bootstrapping during SSR rendering, optimizing performance. If not provided or set to `false`, the default behavior of bootstrapping the root component(s) during initialization is maintained. Context: angular/angular-cli#29085
Introduced the `ENABLE_ROOT_COMPONENT_BOOTSTRAP` token to control the bootstrapping of components during application initialization. This token is utilized by the Angular CLI in the `@angular/ssr` package, particularly during server-side rendering (SSR) when extracting routes. When set to `false`, this token prevents the root component from being bootstrapped during SSR's route extraction phase, which is crucial for efficiently extracting routes without triggering component initialization. This mechanism separates the concerns of route extraction and component bootstrapping during SSR rendering, optimizing performance. If not provided or set to `true`, the default behavior of bootstrapping the root component(s) during initialization is maintained. Context: angular/angular-cli#29085
…ction This commit disables component bootstrapping during route extraction to prevent invoking the AppComponent and its lifecycle hooks. Closes angular#29085
…ction This commit disables component bootstrapping during route extraction to prevent invoking the AppComponent and its lifecycle hooks. Closes angular#29085
…ction This commit disables component bootstrapping during route extraction to prevent invoking the AppComponent and its lifecycle hooks. Closes angular#29085
…ction This commit disables component bootstrapping during route extraction to prevent invoking the AppComponent and its lifecycle hooks. Closes #29085
@alan-agius4 Just to make sure, the route guards are included in this right? Cause i'm currently facing the issue with a canActivateFn that is making an api call. Edit: I just saw it's already included in 19.0.5. For some reason it's not working for me. I still get calls to the root component during build time (with an empty REQUEST token). |
As an additional data point. |
Introduced the `ENABLE_ROOT_COMPONENT_BOOTSTRAP` token to control the bootstrapping of components during application initialization. This token is utilized by the Angular CLI in the `@angular/ssr` package, particularly during server-side rendering (SSR) when extracting routes. When set to `false`, this token prevents the root component from being bootstrapped during SSR's route extraction phase, which is crucial for efficiently extracting routes without triggering component initialization. This mechanism separates the concerns of route extraction and component bootstrapping during SSR rendering, optimizing performance. If not provided or set to `true`, the default behavior of bootstrapping the root component(s) during initialization is maintained. Context: angular/angular-cli#29085
Introduced the `ENABLE_ROOT_COMPONENT_BOOTSTRAP` token to control the bootstrapping of components during application initialization. This token is utilized by the Angular CLI in the `@angular/ssr` package, particularly during server-side rendering (SSR) when extracting routes. When set to `false`, this token prevents the root component from being bootstrapped during SSR's route extraction phase, which is crucial for efficiently extracting routes without triggering component initialization. This mechanism separates the concerns of route extraction and component bootstrapping during SSR rendering, optimizing performance. If not provided or set to `true`, the default behavior of bootstrapping the root component(s) during initialization is maintained. Context: angular/angular-cli#29085
Introduced the `ENABLE_ROOT_COMPONENT_BOOTSTRAP` token to control the bootstrapping of components during application initialization. This token is utilized by the Angular CLI in the `@angular/ssr` package, particularly during server-side rendering (SSR) when extracting routes. When set to `false`, this token prevents the root component from being bootstrapped during SSR's route extraction phase, which is crucial for efficiently extracting routes without triggering component initialization. This mechanism separates the concerns of route extraction and component bootstrapping during SSR rendering, optimizing performance. If not provided or set to `true`, the default behavior of bootstrapping the root component(s) during initialization is maintained. Context: angular/angular-cli#29085
Introduced the `ENABLE_ROOT_COMPONENT_BOOTSTRAP` token to control the bootstrapping of components during application initialization. This token is utilized by the Angular CLI in the `@angular/ssr` package, particularly during server-side rendering (SSR) when extracting routes. When set to `false`, this token prevents the root component from being bootstrapped during SSR's route extraction phase, which is crucial for efficiently extracting routes without triggering component initialization. This mechanism separates the concerns of route extraction and component bootstrapping during SSR rendering, optimizing performance. If not provided or set to `true`, the default behavior of bootstrapping the root component(s) during initialization is maintained. Context: angular/angular-cli#29085 PR Close #59133
Introduced the `ENABLE_ROOT_COMPONENT_BOOTSTRAP` token to control the bootstrapping of components during application initialization. This token is utilized by the Angular CLI in the `@angular/ssr` package, particularly during server-side rendering (SSR) when extracting routes. When set to `false`, this token prevents the root component from being bootstrapped during SSR's route extraction phase, which is crucial for efficiently extracting routes without triggering component initialization. This mechanism separates the concerns of route extraction and component bootstrapping during SSR rendering, optimizing performance. If not provided or set to `true`, the default behavior of bootstrapping the root component(s) during initialization is maintained. Context: angular/angular-cli#29085 PR Close #59205
@alan-agius4 Sorry If I'm not in the good issue or It the topic has been addressed somewhere else (I haven't found it), I'm not clear about dynamic route paths (fetched from an API for example). Let's say my app has no static routes, but only routes paths based on an API. During APP_INITIALIZER the router config is updated using In this case, since all routes paths are built dynamically, in the server.config I have this : provideServerRoutesConfig(
[{ path: '**', renderMode: RenderMode.Server }]
) While provideRouter looks like this provideRouter([]) If I understand well, during the build, the app bootstrap is designed to extract the router config before the first SSR request. So my question is, if a route path has changed, or another path is added after the app build, what is supposed to happen ? Ex :
is now
What happens if I reach Thank a lot for your explanation ! |
I dont want to be that type of guy that just reopens a issue. But i only saw @alan-agius4 answers on that topic and i would kindly ask other angular engineers about their opinion and if its something that can be solved differently. Maybe without @alan-agius4 indirect implication that it would "only" be solveable with file based routing.
There are no docs on route extraction, but my understanding now is that all routes are computed in advance. I'm not deeper into angular code than the public_api, but I can't imagine that a full application load (full lifecycle or template execution) are necessary to figure this out. What does this have to do with route extraction?
proof of concept
In this example, it would only make sense for SSG if the REQUEST token is not available on the server. (but according to @alan-agius4 its "bad practice" to think that the
REQUEST
token is available on the server with disabled prerender) - Just think about that for a second.Sorry if I'm a bit salty, but it took me a really long time to figure out that (imo this bug) is due to the angular dev server.
Related to:
#28995
#28727 (comment)
#29084 (my previous ticket)
Angular Discord - My thread
Angular Discord - Another thread
and probably many more
The text was updated successfully, but these errors were encountered: