Skip to content

Commit 70d0639

Browse files
authored
fix(core): introduce BootstrapContext for improved server bootstrapping (#63639)
* 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.
1 parent 6f6db99 commit 70d0639

File tree

30 files changed

+571
-157
lines changed

30 files changed

+571
-157
lines changed

.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

.github/workflows/dev-infra.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ jobs:
1212
labels:
1313
runs-on: ubuntu-latest
1414
steps:
15-
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
16-
- uses: angular/dev-infra/github-actions/commit-message-based-labels@1f047e7dbae43ea969c2cafb53b33207e86b800f
15+
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
16+
- uses: angular/dev-infra/github-actions/pull-request-labeling@4b4659eabe75a67cebf4692c3c88a98275c67200
1717
with:
1818
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
1919
post_approval_changes:
2020
runs-on: ubuntu-latest
2121
steps:
22-
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
23-
- uses: angular/dev-infra/github-actions/post-approval-changes@1f047e7dbae43ea969c2cafb53b33207e86b800f
22+
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
23+
- uses: angular/dev-infra/github-actions/post-approval-changes@4b4659eabe75a67cebf4692c3c88a98275c67200
2424
with:
2525
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}

WORKSPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ yarn_install(
8383
YARN_LABEL,
8484
"//:.yarnrc",
8585
"//:tools/npm-patches/@angular+ng-dev+0.0.0-a6dcd24107d12114198251ee5d20cda814a1986a.patch",
86+
"//:tools/npm-patches/@angular+ssr+19.2.0-next.2.patch",
8687
"//:tools/npm-patches/@bazel+jasmine+5.8.1.patch",
8788
"//tools:postinstall-patches.js",
8889
"//tools/esm-interop:patches/npm/@angular+build-tooling+0.0.0-2670abf637fa155971cdd1f7e570a7f234922a65.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, context?: 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

0 commit comments

Comments
 (0)