Skip to content

Commit 3c17c4f

Browse files
committed
fix(core): introduce BootstrapContext for improved server bootstrapping
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. (cherry picked from commit 8bf80c9)
1 parent 6f6db99 commit 3c17c4f

30 files changed

Lines changed: 576 additions & 153 deletions

File tree

.aspect/rules/external_repository_action_cache/npm_translate_lock_MzA5NzUwNzMx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
package.json=-1892818434
66
packages/compiler-cli/package.json=-1396217149
77
packages/compiler/package.json=499550843
8-
pnpm-lock.yaml=-1041360686
8+
pnpm-lock.yaml=-903408509
99
pnpm-workspace.yaml=353334404
1010
tools/bazel/rules_angular_store/package.json=-239561259
1111
yarn.lock=1636150847

WORKSPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ yarn_install(
8484
"//:.yarnrc",
8585
"//:tools/npm-patches/@angular+ng-dev+0.0.0-a6dcd24107d12114198251ee5d20cda814a1986a.patch",
8686
"//:tools/npm-patches/@bazel+jasmine+5.8.1.patch",
87+
"//:tools/npm-patches/@angular+ssr+19.2.0-next.2.patch",
8788
"//tools:postinstall-patches.js",
8889
"//tools/esm-interop:patches/npm/@angular+build-tooling+0.0.0-2670abf637fa155971cdd1f7e570a7f234922a65.patch",
8990
"//tools/esm-interop:patches/npm/@bazel+concatjs+5.8.1.patch",

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
@@ -29,7 +29,12 @@ import { Version } from '@angular/core';
2929
export type ApplicationConfig = ApplicationConfig_2;
3030

3131
// @public
32-
export function bootstrapApplication(rootComponent: Type<unknown>, options?: ApplicationConfig): Promise<ApplicationRef>;
32+
export function bootstrapApplication(rootComponent: Type<unknown>, options?: ApplicationConfig, bootstrapContext?: BootstrapContext): Promise<ApplicationRef>;
33+
34+
// @public
35+
export interface BootstrapContext {
36+
platformRef: PlatformRef;
37+
}
3338

3439
// @public
3540
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

packages/core/schematics/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ rollup_bundle(
6767
"//packages/core/schematics/migrations/explicit-standalone-flag:index.ts": "explicit-standalone-flag",
6868
"//packages/core/schematics/migrations/pending-tasks:index.ts": "pending-tasks",
6969
"//packages/core/schematics/migrations/provide-initializer:index.ts": "provide-initializer",
70+
"//packages/core/schematics/migrations/add-bootstrap-context-to-server-main:index.ts": "add-bootstrap-context-to-server-main",
7071
},
7172
format = "cjs",
7273
link_workspace_root = True,
@@ -79,6 +80,7 @@ rollup_bundle(
7980
"//packages/core/schematics/migrations/explicit-standalone-flag",
8081
"//packages/core/schematics/migrations/pending-tasks",
8182
"//packages/core/schematics/migrations/provide-initializer",
83+
"//packages/core/schematics/migrations/add-bootstrap-context-to-server-main",
8284
"//packages/core/schematics/ng-generate/cleanup-unused-imports",
8385
"//packages/core/schematics/ng-generate/control-flow-migration",
8486
"//packages/core/schematics/ng-generate/inject-migration",

0 commit comments

Comments
 (0)