Skip to content

Commit 28926ba

Browse files
alan-agius4atscott
authored andcommitted
feat(core): introduce BootstrapContext for improved server bootstrapping (#63562)
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. PR Close #63562
1 parent 3dc5056 commit 28926ba

File tree

29 files changed

+558
-82
lines changed

29 files changed

+558
-82
lines changed

adev/src/main.server.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
import {bootstrapApplication} from '@angular/platform-browser';
9+
import {bootstrapApplication, BootstrapContext} from '@angular/platform-browser';
1010
import {AppComponent} from './app/app.component';
1111
import {config} from './app/app.config.server';
1212

13-
const bootstrap = () => bootstrapApplication(AppComponent, config);
13+
const bootstrap = (context: BootstrapContext) =>
14+
bootstrapApplication(AppComponent, config, context);
1415

1516
export default bootstrap;

goldens/public-api/platform-browser/index.api.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,12 @@ import { Type } from '@angular/core';
2626
import { Version } from '@angular/core';
2727

2828
// @public
29-
export function bootstrapApplication(rootComponent: Type<unknown>, options?: ApplicationConfig): Promise<ApplicationRef>;
29+
export function bootstrapApplication(rootComponent: Type<unknown>, options?: ApplicationConfig, context?: BootstrapContext): Promise<ApplicationRef>;
30+
31+
// @public
32+
export interface BootstrapContext {
33+
platformRef: PlatformRef;
34+
}
3035

3136
// @public
3237
export class BrowserModule {

goldens/public-api/platform-server/index.api.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
```ts
66

77
import { ApplicationRef } from '@angular/core';
8+
import { BootstrapContext } from '@angular/platform-browser';
89
import { EnvironmentProviders } from '@angular/core';
910
import * as i0 from '@angular/core';
1011
import * as i1 from '@angular/platform-browser';
@@ -27,7 +28,7 @@ export interface PlatformConfig {
2728
url?: string;
2829
}
2930

30-
// @public (undocumented)
31+
// @public
3132
export function platformServer(extraProviders?: StaticProvider[] | undefined): PlatformRef;
3233

3334
// @public
@@ -45,7 +46,7 @@ export class PlatformState {
4546
export function provideServerRendering(): EnvironmentProviders;
4647

4748
// @public
48-
export function renderApplication<T>(bootstrap: () => Promise<ApplicationRef>, options: {
49+
export function renderApplication(bootstrap: (context: BootstrapContext) => Promise<ApplicationRef>, options: {
4950
document?: string | Document;
5051
url?: string;
5152
platformProviders?: Provider[];
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 {bootstrapApplication, BootstrapContext} from '@angular/platform-browser';
22
import {AppComponent} from './app/app.component';
33
import {config} from './app/app.config.server';
44

5-
const bootstrap = () => bootstrapApplication(AppComponent, config);
5+
const bootstrap = (context: BootstrapContext) =>
6+
bootstrapApplication(AppComponent, config, context);
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 {bootstrapApplication, BootstrapContext} from '@angular/platform-browser';
22
import {AppComponent} from './app/app.component';
33
import {config} from './app/app.config.server';
44

5-
const bootstrap = () => bootstrapApplication(AppComponent, config);
5+
const bootstrap = (context: BootstrapContext) =>
6+
bootstrapApplication(AppComponent, config, context);
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 {bootstrapApplication, BootstrapContext} from '@angular/platform-browser';
22
import {AppComponent} from './app/app.component';
33
import {config} from './app/app.config.server';
44

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

78
export default bootstrap;

modules/ssr-benchmarks/src/main.server.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@
77
*/
88

99
import {ɵenableProfiling} from '@angular/core';
10-
import {bootstrapApplication} from '@angular/platform-browser';
10+
import {bootstrapApplication, BootstrapContext} from '@angular/platform-browser';
1111
import {AppComponent} from './app/app.component';
1212
import {config} from './app/app.config.server';
1313
import {renderApplication, ɵENABLE_DOM_EMULATION} from '@angular/platform-server';
1414

15-
const bootstrap = () => bootstrapApplication(AppComponent, config);
15+
const bootstrap = (context: BootstrapContext) =>
16+
bootstrapApplication(AppComponent, config, context);
1617

1718
/**
1819
* Function that will profile the server-side rendering

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,8 @@
220220
},
221221
"pnpm": {
222222
"patchedDependencies": {
223-
"[email protected]": "tools/pnpm-patches/dagre-d3-es+7.0.11.patch"
223+
"[email protected]": "tools/pnpm-patches/dagre-d3-es+7.0.11.patch",
224+
"@angular/ssr": "tools/pnpm-patches/@angular__ssr.patch"
224225
},
225226
"packageExtensions": {
226227
"grpc-gcp": {

packages/core/schematics/BUILD.bazel

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ bundle_entrypoints = [
114114
"application-config-core",
115115
"packages/core/schematics/migrations/application-config-core/index.js",
116116
],
117+
[
118+
"add-bootstrap-context-to-server-main",
119+
"packages/core/schematics/migrations/add-bootstrap-context-to-server-main/index.js",
120+
],
117121
]
118122

119123
rollup.rollup(
@@ -125,6 +129,7 @@ rollup.rollup(
125129
"//:node_modules/magic-string",
126130
"//:node_modules/semver",
127131
"//packages/core/schematics:tsconfig_build",
132+
"//packages/core/schematics/migrations/add-bootstrap-context-to-server-main",
128133
"//packages/core/schematics/migrations/application-config-core",
129134
"//packages/core/schematics/migrations/control-flow-migration",
130135
"//packages/core/schematics/migrations/ngclass-to-class-migration",

packages/core/schematics/migrations.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121
"version": "21.0.0",
2222
"description": "Moves imports of `ApplicationConfig` from `@angular/platform-browser` to `@angular/core`",
2323
"factory": "./bundles/application-config-core.cjs#migrate"
24+
},
25+
"add-bootstrap-context-to-server-main": {
26+
"version": "21.0.0",
27+
"description": "Adds `BootstrapContext` to `bootstrapApplication` calls in `main.server.ts` to support server rendering.",
28+
"factory": "./bundles/add-bootstrap-context-to-server-main.cjs#migrate"
2429
}
2530
}
2631
}

0 commit comments

Comments
 (0)