Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit a81c176

Browse files
feat(@angular/ssr): introduce BootstrapContext for isolated server-side rendering
This commit introduces a number of changes to the server bootstrapping process to make it more robust and less error-prone, especially for concurrent requests. Previously, the server rendering process relied on a module-level global platform injector. This could lead to issues in server-side rendering environments where multiple requests are processed concurrently, as they could inadvertently share or overwrite the global injector state. The new approach introduces a `BootstrapContext` that is passed to the `bootstrapApplication` function. This context provides a platform reference that is scoped to the individual request, ensuring that each server-side render has an isolated platform injector. This prevents state leakage between concurrent requests and makes the overall process more reliable. BREAKING CHANGE: The server-side bootstrapping process has been changed to eliminate the reliance on a global platform injector. Before: ```ts const bootstrap = () => bootstrapApplication(AppComponent, config); ``` After: ```ts const bootstrap = (context: BootstrapContext) => bootstrapApplication(AppComponent, config, context); ``` A schematic is provided to automatically update `main.server.ts` files to pass the `BootstrapContext` to the `bootstrapApplication` call. In addition, `getPlatform()` and `destroyPlatform()` will now return `null` and be a no-op respectively when running in a server environment.
1 parent e6a3b55 commit a81c176

File tree

6 files changed

+26
-17
lines changed

6 files changed

+26
-17
lines changed

‎packages/angular/ssr/node/src/common-engine/common-engine.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
import { ApplicationRef, StaticProvider, Type } from '@angular/core';
10+
import { BootstrapContext } from '@angular/platform-browser';
1011
import { renderApplication, renderModule, ɵSERVER_CONTEXT } from '@angular/platform-server';
1112
import * as fs from 'node:fs';
1213
import { dirname, join, normalize, resolve } from 'node:path';
@@ -23,7 +24,7 @@ const SSG_MARKER_REGEXP = /ng-server-context=["']\w*\|?ssg\|?\w*["']/;
2324

2425
export interface CommonEngineOptions {
2526
/** A method that when invoked returns a promise that returns an `ApplicationRef` instance once resolved or an NgModule. */
26-
bootstrap?: Type<{}> | (() => Promise<ApplicationRef>);
27+
bootstrap?: Type<{}> | ((context: BootstrapContext) => Promise<ApplicationRef>);
2728

2829
/** A set of platform level providers for all requests. */
2930
providers?: StaticProvider[];

‎packages/angular/ssr/src/routes/ng-routes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ export async function getRoutesFromAngularRouterConfig(
634634
const moduleRef = await platformRef.bootstrapModule(bootstrap);
635635
applicationRef = moduleRef.injector.get(ApplicationRef);
636636
} else {
637-
applicationRef = await bootstrap();
637+
applicationRef = await bootstrap({ platformRef });
638638
}
639639

640640
const injector = applicationRef.injector;

‎packages/angular/ssr/src/routes/route-config.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -356,20 +356,23 @@ export function withAppShell(
356356
* when using the `bootstrapApplication` function:
357357
*
358358
* ```ts
359-
* import { bootstrapApplication } from '@angular/platform-browser';
359+
* import { bootstrapApplication, BootstrapContext } from '@angular/platform-browser';
360360
* import { provideServerRendering, withRoutes, withAppShell } from '@angular/ssr';
361361
* import { AppComponent } from './app/app.component';
362362
* import { SERVER_ROUTES } from './app/app.server.routes';
363363
* import { AppShellComponent } from './app/app-shell.component';
364364
*
365-
* bootstrapApplication(AppComponent, {
366-
* providers: [
367-
* provideServerRendering(
368-
* withRoutes(SERVER_ROUTES),
369-
* withAppShell(AppShellComponent)
370-
* )
371-
* ]
372-
* });
365+
* const bootstrap = (context: BootstrapContext) =>
366+
* bootstrapApplication(AppComponent, {
367+
* providers: [
368+
* provideServerRendering(
369+
* withRoutes(SERVER_ROUTES),
370+
* withAppShell(AppShellComponent),
371+
* ),
372+
* ],
373+
* }, context);
374+
*
375+
* export default bootstrap;
373376
* ```
374377
* @see {@link withRoutes} configures server-side routing
375378
* @see {@link withAppShell} configures the application shell

‎packages/angular/ssr/src/utils/ng.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
type Type,
1515
ɵConsole,
1616
} from '@angular/core';
17+
import { BootstrapContext } from '@angular/platform-browser';
1718
import {
1819
INITIAL_CONFIG,
1920
ɵSERVER_CONTEXT as SERVER_CONTEXT,
@@ -31,7 +32,9 @@ import { joinUrlParts, stripIndexHtmlFromURL } from './url';
3132
* - A reference to an Angular component or module (`Type<unknown>`) that serves as the root of the application.
3233
* - A function that returns a `Promise<ApplicationRef>`, which resolves with the root application reference.
3334
*/
34-
export type AngularBootstrap = Type<unknown> | (() => Promise<ApplicationRef>);
35+
export type AngularBootstrap =
36+
| Type<unknown>
37+
| ((context: BootstrapContext) => Promise<ApplicationRef>);
3538

3639
/**
3740
* Renders an Angular application or module to an HTML string.
@@ -90,7 +93,7 @@ export async function renderAngular(
9093
const moduleRef = await platformRef.bootstrapModule(bootstrap);
9194
applicationRef = moduleRef.injector.get(ApplicationRef);
9295
} else {
93-
applicationRef = await bootstrap();
96+
applicationRef = await bootstrap({ platformRef });
9497
}
9598

9699
// Block until application is stable.
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { bootstrapApplication } from '@angular/platform-browser';
1+
import { BootstrapContext, bootstrapApplication } from '@angular/platform-browser';
22
import { <%= appComponentName %> } from '<%= appComponentPath %>';
33
import { config } from './app/app.config.server';
44

5-
const bootstrap = () => bootstrapApplication(<%= appComponentName %>, config);
5+
const bootstrap = (context: BootstrapContext) =>
6+
bootstrapApplication(<%= appComponentName %>, config, BootstrapContext);
67

78
export default bootstrap;
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { bootstrapApplication } from '@angular/platform-browser';
1+
import { BootstrapContext, bootstrapApplication } from '@angular/platform-browser';
22
import { <%= appComponentName %> } from '<%= appComponentPath %>';
33
import { config } from './app/app.config.server';
44

5-
const bootstrap = () => bootstrapApplication(<%= appComponentName %>, config);
5+
const bootstrap = (context: BootstrapContext) =>
6+
bootstrapApplication(<%= appComponentName %>, config, BootstrapContext);
67

78
export default bootstrap;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /