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.
This commit is contained in:
Alan Agius
2025-09-09 19:56:38 +02:00
committed by GitHub
parent 6f6db999cd
commit 70d0639bc1
30 changed files with 571 additions and 157 deletions
@@ -5,7 +5,7 @@
package.json=-1892818434
packages/compiler-cli/package.json=-1396217149
packages/compiler/package.json=499550843
pnpm-lock.yaml=-1041360686
pnpm-lock.yaml=-903408509
pnpm-workspace.yaml=353334404
tools/bazel/rules_angular_store/package.json=-239561259
yarn.lock=1636150847
+4 -4
View File
@@ -12,14 +12,14 @@ jobs:
labels:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: angular/dev-infra/github-actions/commit-message-based-labels@1f047e7dbae43ea969c2cafb53b33207e86b800f
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: angular/dev-infra/github-actions/pull-request-labeling@4b4659eabe75a67cebf4692c3c88a98275c67200
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
post_approval_changes:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: angular/dev-infra/github-actions/post-approval-changes@1f047e7dbae43ea969c2cafb53b33207e86b800f
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: angular/dev-infra/github-actions/post-approval-changes@4b4659eabe75a67cebf4692c3c88a98275c67200
with:
angular-robot-key: ${{ secrets.ANGULAR_ROBOT_PRIVATE_KEY }}
+1
View File
@@ -83,6 +83,7 @@ yarn_install(
YARN_LABEL,
"//:.yarnrc",
"//:tools/npm-patches/@angular+ng-dev+0.0.0-a6dcd24107d12114198251ee5d20cda814a1986a.patch",
"//:tools/npm-patches/@angular+ssr+19.2.0-next.2.patch",
"//:tools/npm-patches/@bazel+jasmine+5.8.1.patch",
"//tools:postinstall-patches.js",
"//tools/esm-interop:patches/npm/@angular+build-tooling+0.0.0-2670abf637fa155971cdd1f7e570a7f234922a65.patch",
+3 -2
View File
@@ -6,10 +6,11 @@
* found in the LICENSE file at https://angular.dev/license
*/
import {bootstrapApplication} from '@angular/platform-browser';
import {bootstrapApplication, BootstrapContext} from '@angular/platform-browser';
import {AppComponent} from './app/app.component';
import {config} from './app/app.config.server';
const bootstrap = () => bootstrapApplication(AppComponent, config);
const bootstrap = (context: BootstrapContext) =>
bootstrapApplication(AppComponent, config, context);
export default bootstrap;
@@ -29,7 +29,12 @@ import { Version } from '@angular/core';
export type ApplicationConfig = ApplicationConfig_2;
// @public
export function bootstrapApplication(rootComponent: Type<unknown>, options?: ApplicationConfig): Promise<ApplicationRef>;
export function bootstrapApplication(rootComponent: Type<unknown>, options?: ApplicationConfig, context?: BootstrapContext): Promise<ApplicationRef>;
// @public
export interface BootstrapContext {
platformRef: PlatformRef;
}
// @public
export class BrowserModule {
@@ -5,6 +5,7 @@
```ts
import { ApplicationRef } from '@angular/core';
import { BootstrapContext } from '@angular/platform-browser';
import { EnvironmentProviders } from '@angular/core';
import * as i0 from '@angular/core';
import * as i1 from '@angular/platform-browser';
@@ -27,7 +28,7 @@ export interface PlatformConfig {
url?: string;
}
// @public (undocumented)
// @public
export function platformServer(extraProviders?: StaticProvider[] | undefined): PlatformRef;
// @public
@@ -45,7 +46,7 @@ export class PlatformState {
export function provideServerRendering(): EnvironmentProviders;
// @public
export function renderApplication<T>(bootstrap: () => Promise<ApplicationRef>, options: {
export function renderApplication(bootstrap: (context: BootstrapContext) => Promise<ApplicationRef>, options: {
document?: string | Document;
url?: string;
platformProviders?: Provider[];
@@ -1,7 +1,8 @@
import {bootstrapApplication} from '@angular/platform-browser';
import {bootstrapApplication, BootstrapContext} from '@angular/platform-browser';
import {AppComponent} from './app/app.component';
import {config} from './app/app.config.server';
const bootstrap = () => bootstrapApplication(AppComponent, config);
const bootstrap = (context: BootstrapContext) =>
bootstrapApplication(AppComponent, config, context);
export default bootstrap;
@@ -1,7 +1,8 @@
import {bootstrapApplication} from '@angular/platform-browser';
import {bootstrapApplication, BootstrapContext} from '@angular/platform-browser';
import {AppComponent} from './app/app.component';
import {config} from './app/app.config.server';
const bootstrap = () => bootstrapApplication(AppComponent, config);
const bootstrap = (context: BootstrapContext) =>
bootstrapApplication(AppComponent, config, context);
export default bootstrap;
@@ -1,7 +1,8 @@
import {bootstrapApplication} from '@angular/platform-browser';
import {bootstrapApplication, BootstrapContext} from '@angular/platform-browser';
import {AppComponent} from './app/app.component';
import {config} from './app/app.config.server';
const bootstrap = () => bootstrapApplication(AppComponent, config);
const bootstrap = (context: BootstrapContext) =>
bootstrapApplication(AppComponent, config, context);
export default bootstrap;
+3 -2
View File
@@ -7,12 +7,13 @@
*/
import {ɵenableProfiling} from '@angular/core';
import {bootstrapApplication} from '@angular/platform-browser';
import {bootstrapApplication, BootstrapContext} from '@angular/platform-browser';
import {AppComponent} from './app/app.component';
import {config} from './app/app.config.server';
import {renderApplication, ɵENABLE_DOM_EMULATION} from '@angular/platform-server';
const bootstrap = () => bootstrapApplication(AppComponent, config);
const bootstrap = (context: BootstrapContext) =>
bootstrapApplication(AppComponent, config, context);
/**
* Function that will profile the server-side rendering
+2
View File
@@ -67,6 +67,7 @@ rollup_bundle(
"//packages/core/schematics/migrations/explicit-standalone-flag:index.ts": "explicit-standalone-flag",
"//packages/core/schematics/migrations/pending-tasks:index.ts": "pending-tasks",
"//packages/core/schematics/migrations/provide-initializer:index.ts": "provide-initializer",
"//packages/core/schematics/migrations/add-bootstrap-context-to-server-main:index.ts": "add-bootstrap-context-to-server-main",
},
format = "cjs",
link_workspace_root = True,
@@ -76,6 +77,7 @@ rollup_bundle(
"//packages/core/schematics/test:__pkg__",
],
deps = [
"//packages/core/schematics/migrations/add-bootstrap-context-to-server-main",
"//packages/core/schematics/migrations/explicit-standalone-flag",
"//packages/core/schematics/migrations/pending-tasks",
"//packages/core/schematics/migrations/provide-initializer",
+5
View File
@@ -15,6 +15,11 @@
"description": "Replaces `APP_INITIALIZER`, `ENVIRONMENT_INITIALIZER` & `PLATFORM_INITIALIZER` respectively with `provideAppInitializer`, `provideEnvironmentInitializer` & `providePlatformInitializer`.",
"factory": "./bundles/provide-initializer.cjs#migrate",
"optional": true
},
"add-bootstrap-context-to-server-main": {
"version": "19.2.15",
"description": "Adds `BootstrapContext` to `bootstrapApplication` calls in `main.server.ts` to support server rendering.",
"factory": "./bundles/add-bootstrap-context-to-server-main.cjs#migrate"
}
}
}
@@ -0,0 +1,21 @@
load("//tools:defaults2.bzl", "ts_project")
package(
default_visibility = [
"//packages/core/schematics:__pkg__",
"//packages/core/schematics/test:__pkg__",
],
)
ts_project(
name = "add-bootstrap-context-to-server-main",
srcs = glob(["**/*.ts"]),
interop_deps = [
"//packages/compiler-cli/private",
"//packages/core/schematics/utils",
],
deps = [
"//:node_modules/@angular-devkit/schematics",
"//:node_modules/typescript",
],
)
@@ -0,0 +1,15 @@
# Add Bootstrap Context to Server Main Migration
This schematic updates `main.server.ts` files to correctly handle server-side rendering with `bootstrapApplication`.
## How it works
The migration performs the following transformations:
1. **Identifies `bootstrapApplication` calls:** It specifically targets `main.server.ts` files to find calls to `bootstrapApplication` that are missing a third `context` argument.
2. **Updates the function signature:** It adds a `(context: BootstrapContext)` parameter to the arrow function that typically wraps the `bootstrapApplication` call in a server entry file.
3. **Passes the context:** It adds `, context` to the `bootstrapApplication` call, passing the newly added parameter.
4. **Updates imports:** It ensures that `BootstrapContext` is imported from `@angular/platform-browser`.
@@ -0,0 +1,58 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {Rule, SchematicsException, Tree, UpdateRecorder} from '@angular-devkit/schematics';
import {relative} from 'path';
import {getProjectTsConfigPaths} from '../../utils/project_tsconfig_paths';
import {canMigrateFile, createMigrationProgram} from '../../utils/typescript/compiler_host';
import {migrateFile} from './migration';
export function migrate(): Rule {
return async (tree: Tree) => {
const {buildPaths, testPaths} = await getProjectTsConfigPaths(tree);
const basePath = process.cwd();
const allPaths = [...buildPaths, ...testPaths];
if (!allPaths.length) {
throw new SchematicsException(
'Could not find any tsconfig file. Cannot run the add-bootstrap-context-to-server-main migration.',
);
}
for (const tsconfigPath of allPaths) {
runMigration(tree, tsconfigPath, basePath);
}
};
}
function runMigration(tree: Tree, tsconfigPath: string, basePath: string) {
const program = createMigrationProgram(tree, tsconfigPath, basePath);
const sourceFiles = program
.getSourceFiles()
.filter((sourceFile) => canMigrateFile(basePath, sourceFile, program));
for (const sourceFile of sourceFiles) {
let update: UpdateRecorder | null = null;
const rewriter = (startPos: number, width: number, text: string | null) => {
if (update === null) {
// Lazily initialize update, because most files will not require migration.
update = tree.beginUpdate(relative(basePath, sourceFile.fileName));
}
update.remove(startPos, width);
if (text !== null) {
update.insertLeft(startPos, text);
}
};
migrateFile(sourceFile, rewriter);
if (update !== null) {
tree.commitUpdate(update);
}
}
}
@@ -0,0 +1,78 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {ImportManager} from '@angular/compiler-cli/private/migrations';
import ts from 'typescript';
type Rewriter = (startPos: number, width: number, text: string | null) => void;
function findArrowFunction(node: ts.Node): ts.ArrowFunction | undefined {
let current: ts.Node | undefined = node;
while (current) {
if (ts.isArrowFunction(current)) {
return current;
}
current = current.parent;
}
return undefined;
}
export function migrateFile(sourceFile: ts.SourceFile, rewriter: Rewriter) {
if (!sourceFile.fileName.endsWith('main.server.ts')) {
return;
}
const bootstrapAppCalls: ts.CallExpression[] = [];
ts.forEachChild(sourceFile, function findCalls(node) {
if (
ts.isCallExpression(node) &&
ts.isIdentifier(node.expression) &&
node.expression.text === 'bootstrapApplication' &&
node.arguments.length < 3
) {
bootstrapAppCalls.push(node);
}
ts.forEachChild(node, findCalls);
});
if (bootstrapAppCalls.length === 0) {
return;
}
const importManager = new ImportManager({
generateUniqueIdentifier: () => null,
shouldUseSingleQuotes: () => true,
});
for (const node of bootstrapAppCalls) {
const end = node.arguments[node.arguments.length - 1].getEnd();
rewriter(end, 0, ', context');
const arrowFunction = findArrowFunction(node);
if (arrowFunction && arrowFunction.parameters.length === 0) {
const pos = arrowFunction.parameters.end;
rewriter(pos, 0, 'context: BootstrapContext');
}
}
importManager.addImport({
exportSymbolName: 'BootstrapContext',
exportModuleSpecifier: '@angular/platform-browser',
requestedFile: sourceFile,
});
const finalization = importManager.finalize();
const printer = ts.createPrinter();
for (const [oldBindings, newBindings] of finalization.updatedImports) {
const newText = printer.printNode(ts.EmitHint.Unspecified, newBindings, sourceFile);
const start = oldBindings.getStart();
const width = oldBindings.getWidth();
rewriter(start, width, newText);
}
}
@@ -0,0 +1,169 @@
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import {getSystemPath, normalize, virtualFs} from '@angular-devkit/core';
import {TempScopedNodeJsSyncHost} from '@angular-devkit/core/node/testing';
import {HostTree} from '@angular-devkit/schematics';
import {SchematicTestRunner, UnitTestTree} from '@angular-devkit/schematics/testing/index.js';
import {runfiles} from '@bazel/runfiles';
import shx from 'shelljs';
describe('bootstrapApplication for server migration', () => {
let runner: SchematicTestRunner;
let host: TempScopedNodeJsSyncHost;
let tree: UnitTestTree;
let tmpDirPath: string;
function writeFile(filePath: string, contents: string) {
host.sync.write(normalize(filePath), virtualFs.stringToFileBuffer(contents));
}
function runMigration() {
return runner.runSchematic('add-bootstrap-context-to-server-main', {}, tree);
}
beforeEach(() => {
runner = new SchematicTestRunner('test', runfiles.resolvePackageRelative('../migrations.json'));
host = new TempScopedNodeJsSyncHost();
tree = new UnitTestTree(new HostTree(host));
writeFile('/tsconfig.json', '{}');
writeFile(
'/angular.json',
JSON.stringify({
version: 1,
projects: {
t: {
root: '',
architect: {
build: {options: {tsConfig: './tsconfig.json'}},
server: {options: {main: './main.server.ts'}},
},
},
},
}),
);
tmpDirPath = getSystemPath(host.root);
// Switch into the temporary directory path. This allows us to run
// the schematic against our custom unit test tree.
shx.cd(tmpDirPath);
});
it('should add BootstrapContext to bootstrapApplication call', async () => {
const inputContent = `
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { config } from './app/app.config.server';
const bootstrap = () => bootstrapApplication(AppComponent, config);
export default bootstrap;
`;
const expectedContent = `
import { bootstrapApplication, BootstrapContext } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { config } from './app/app.config.server';
const bootstrap = (context: BootstrapContext) => bootstrapApplication(AppComponent, config, context);
export default bootstrap;
`;
writeFile('/main.server.ts', inputContent);
await runMigration();
const newContent = tree.readContent('/main.server.ts');
expect(newContent).toEqual(expectedContent);
});
it('should add BootstrapContext to bootstrapApplication call in a block body', async () => {
const inputContent = `
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { config } from './app/app.config.server';
const bootstrap = () => {
return bootstrapApplication(AppComponent, config);
};
export default bootstrap;
`;
const expectedContent = `
import { bootstrapApplication, BootstrapContext } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { config } from './app/app.config.server';
const bootstrap = (context: BootstrapContext) => {
return bootstrapApplication(AppComponent, config, context);
};
export default bootstrap;
`;
writeFile('/main.server.ts', inputContent);
await runMigration();
const newContent = tree.readContent('/main.server.ts');
expect(newContent).toEqual(expectedContent);
});
it('should not change bootstrapApplication call that already has a context', async () => {
const inputContent = `
import { bootstrapApplication, BootstrapContext } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { config } from './app/app.config.server';
const bootstrap = (context: BootstrapContext) => bootstrapApplication(AppComponent, config, context);
export default bootstrap;
`;
writeFile('/main.server.ts', inputContent);
await runMigration();
const newContent = tree.readContent('/main.server.ts');
expect(newContent).toEqual(inputContent);
});
it('should add BootstrapContext to existing platform-browser import', async () => {
const inputContent = `
import { bootstrapApplication, BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { config } from './app/app.config.server';
const bootstrap = () => bootstrapApplication(AppComponent, config);
export default bootstrap;
`;
const expectedContent = `
import { bootstrapApplication, BrowserModule, BootstrapContext } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { config } from './app/app.config.server';
const bootstrap = (context: BootstrapContext) => bootstrapApplication(AppComponent, config, context);
export default bootstrap;
`;
writeFile('/main.server.ts', inputContent);
await runMigration();
const newContent = tree.readContent('/main.server.ts');
expect(newContent).toEqual(expectedContent);
});
it('should not modify other files', async () => {
const inputContent = `
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { config } from './app/app.config.server';
const bootstrap = () => bootstrapApplication(AppComponent, config);
export default bootstrap;
`;
writeFile('/main.ts', inputContent);
await runMigration();
const newContent = tree.readContent('/main.ts');
expect(newContent).toEqual(inputContent);
});
});
@@ -20,6 +20,8 @@ import {ChangeDetectionSchedulerImpl} from '../change_detection/scheduling/zonel
import {bootstrap} from '../platform/bootstrap';
import {profiler} from '../render3/profiler';
import {ProfilerEvent} from '../render3/profiler_types';
import {RuntimeError, RuntimeErrorCode} from '../errors';
import {PlatformRef} from '../platform/platform_ref';
/**
* Internal create application API that implements the core application creation logic and optional
@@ -37,17 +39,28 @@ export function internalCreateApplication(config: {
rootComponent?: Type<unknown>;
appProviders?: Array<Provider | EnvironmentProviders>;
platformProviders?: Provider[];
platformRef?: PlatformRef;
}): Promise<ApplicationRef> {
const {rootComponent, appProviders, platformProviders, platformRef} = config;
profiler(ProfilerEvent.BootstrapApplicationStart);
if (typeof ngServerMode !== 'undefined' && ngServerMode && !platformRef) {
throw new RuntimeError(
RuntimeErrorCode.PLATFORM_NOT_FOUND,
ngDevMode &&
'Missing Platform: This may be due to using `bootstrapApplication` on the server without passing a `BootstrapContext`. ' +
'Please make sure that `bootstrapApplication` is called with a `context` argument.',
);
}
try {
const {rootComponent, appProviders, platformProviders} = config;
const platformInjector =
platformRef?.injector ?? createOrReusePlatformInjector(platformProviders as StaticProvider[]);
if ((typeof ngDevMode === 'undefined' || ngDevMode) && rootComponent !== undefined) {
assertStandaloneComponentType(rootComponent);
}
const platformInjector = createOrReusePlatformInjector(platformProviders as StaticProvider[]);
// Create root application injector based on a set of providers configured at the platform
// bootstrap level as well as providers passed to the bootstrap call by a user.
const allAppProviders = [
-1
View File
@@ -122,7 +122,6 @@ export {
restoreComponentResolutionQueue as ɵrestoreComponentResolutionQueue,
} from './metadata/resource_loading';
export {PendingTasksInternal as ɵPendingTasksInternal} from './pending_tasks';
export {ALLOW_MULTIPLE_PLATFORMS as ɵALLOW_MULTIPLE_PLATFORMS} from './platform/platform';
export {ENABLE_ROOT_COMPONENT_BOOTSTRAP as ɵENABLE_ROOT_COMPONENT_BOOTSTRAP} from './platform/bootstrap';
export {ReflectionCapabilities as ɵReflectionCapabilities} from './reflection/reflection_capabilities';
export {AnimationRendererType as ɵAnimationRendererType} from './render/api';
+29 -19
View File
@@ -27,14 +27,6 @@ import {PLATFORM_DESTROY_LISTENERS} from './platform_destroy_listeners';
let _platformInjector: Injector | null = null;
/**
* Internal token to indicate whether having multiple bootstrapped platform should be allowed (only
* one bootstrapped platform is allowed by default). This token helps to support SSR scenarios.
*/
export const ALLOW_MULTIPLE_PLATFORMS = new InjectionToken<boolean>(
ngDevMode ? 'AllowMultipleToken' : '',
);
/**
* Creates a platform.
* Platforms must be created on launch using this function.
@@ -42,15 +34,20 @@ export const ALLOW_MULTIPLE_PLATFORMS = new InjectionToken<boolean>(
* @publicApi
*/
export function createPlatform(injector: Injector): PlatformRef {
if (_platformInjector && !_platformInjector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
if (getPlatform()) {
throw new RuntimeError(
RuntimeErrorCode.MULTIPLE_PLATFORMS,
ngDevMode && 'There can be only one platform. Destroy the previous one to create a new one.',
);
}
publishDefaultGlobalUtils();
publishSignalConfiguration();
_platformInjector = injector;
// During SSR, using this setting and using an injector from the global can cause the
// injector to be used for a different requjest due to concurrency.
_platformInjector = typeof ngServerMode === 'undefined' || !ngServerMode ? injector : null;
const platform = injector.get(PlatformRef);
runPlatformInitializers(injector);
return platform;
@@ -76,19 +73,19 @@ export function createPlatformFactory(
const marker = new InjectionToken(desc);
return (extraProviders: StaticProvider[] = []) => {
let platform = getPlatform();
if (!platform || platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
if (!platform) {
const platformProviders: StaticProvider[] = [
...providers,
...extraProviders,
{provide: marker, useValue: true},
];
if (parentPlatformFactory) {
parentPlatformFactory(platformProviders);
} else {
platform =
parentPlatformFactory?.(platformProviders) ??
createPlatform(createPlatformInjector(platformProviders, desc));
}
}
return assertPlatform(marker);
return typeof ngServerMode !== 'undefined' && ngServerMode ? platform : assertPlatform(marker);
};
}
@@ -114,7 +111,6 @@ function createPlatformInjector(providers: StaticProvider[] = [], name?: string)
*/
export function assertPlatform(requiredToken: any): PlatformRef {
const platform = getPlatform();
if (!platform) {
throw new RuntimeError(RuntimeErrorCode.PLATFORM_NOT_FOUND, ngDevMode && 'No platform exists!');
}
@@ -133,11 +129,16 @@ export function assertPlatform(requiredToken: any): PlatformRef {
}
/**
* Returns the current platform.
* Returns the current platform in the browser environment. In the server environment,
* returns `null`. If you need access to the platform information, inject `PlatformRef` in your application.
*
* @publicApi
*/
export function getPlatform(): PlatformRef | null {
if (typeof ngServerMode !== 'undefined' && ngServerMode) {
return null;
}
return _platformInjector?.get(PlatformRef) ?? null;
}
@@ -145,6 +146,8 @@ export function getPlatform(): PlatformRef | null {
* Destroys the current Angular platform and all Angular applications on the page.
* Destroys all modules and listeners registered with the platform.
*
* This function should not be used in a server environment, as it will be a no-op.
*
* @publicApi
*/
export function destroyPlatform(): void {
@@ -162,9 +165,16 @@ export function createOrReusePlatformInjector(providers: StaticProvider[] = []):
if (_platformInjector) return _platformInjector;
publishDefaultGlobalUtils();
// Otherwise, setup a new platform injector and run platform initializers.
const injector = createPlatformInjector(providers);
_platformInjector = injector;
// During SSR, using this setting and using an injector from the global can cause the
// injector to be used for a different request due to concurrency.
if (typeof ngServerMode === 'undefined' || !ngServerMode) {
_platformInjector = injector;
}
publishSignalConfiguration();
runPlatformInitializers(injector);
return injector;
@@ -1,5 +1,4 @@
[
"ALLOW_MULTIPLE_PLATFORMS",
"APP_BOOTSTRAP_LISTENER",
"APP_ID",
"APP_INITIALIZER",
@@ -661,4 +660,4 @@
"ɵɵproperty",
"ɵɵtemplate",
"ɵɵtext"
]
]
@@ -1,5 +1,4 @@
[
"ALLOW_MULTIPLE_PLATFORMS",
"APP_BOOTSTRAP_LISTENER",
"APP_ID",
"APP_INITIALIZER",
@@ -661,4 +660,4 @@
"ɵɵtext",
"ɵɵtwoWayListener",
"ɵɵtwoWayProperty"
]
]
+23 -2
View File
@@ -62,6 +62,19 @@ import {RuntimeErrorCode} from './errors';
type ApplicationConfig = ApplicationConfigFromCore;
export {ApplicationConfig};
/**
* A context object that can be passed to `bootstrapApplication` to provide a pre-existing platform
* injector.
*
* @publicApi
*/
export interface BootstrapContext {
/**
* A reference to a platform.
*/
platformRef: PlatformRef;
}
/**
* Bootstraps an instance of an Angular application and renders a standalone component as the
* application's root component. More information about standalone components can be found in [this
@@ -117,6 +130,9 @@ export {ApplicationConfig};
* @param rootComponent A reference to a standalone component that should be rendered.
* @param options Extra configuration for the bootstrap operation, see `ApplicationConfig` for
* additional info.
* @param context Optional context object that can be used to provide a pre-existing
* platform injector. This is useful for advanced use-cases, for example, server-side
* rendering, where the platform is created for each request.
* @returns A promise that returns an `ApplicationRef` instance once resolved.
*
* @publicApi
@@ -124,8 +140,13 @@ export {ApplicationConfig};
export function bootstrapApplication(
rootComponent: Type<unknown>,
options?: ApplicationConfig,
context?: BootstrapContext,
): Promise<ApplicationRef> {
return internalCreateApplication({rootComponent, ...createProvidersConfig(options)});
return internalCreateApplication({
rootComponent,
platformRef: context?.platformRef,
...createProvidersConfig(options),
});
}
/**
@@ -140,7 +161,7 @@ export function bootstrapApplication(
*
* @publicApi
*/
export function createApplication(options?: ApplicationConfig) {
export function createApplication(options?: ApplicationConfig): Promise<ApplicationRef> {
return internalCreateApplication(createProvidersConfig(options));
}
@@ -9,6 +9,7 @@
export {
ApplicationConfig,
bootstrapApplication,
BootstrapContext,
BrowserModule,
createApplication,
platformBrowser,
+7 -3
View File
@@ -26,7 +26,6 @@ import {
Provider,
StaticProvider,
Testability,
ɵALLOW_MULTIPLE_PLATFORMS as ALLOW_MULTIPLE_PLATFORMS,
ɵsetDocument,
ɵTESTABILITY as TESTABILITY,
} from '@angular/core';
@@ -54,8 +53,6 @@ export const INTERNAL_SERVER_PLATFORM_PROVIDERS: StaticProvider[] = [
deps: [DOCUMENT, [Optional, INITIAL_CONFIG]],
},
{provide: PlatformState, deps: [DOCUMENT]},
// Add special provider that allows multiple instances of platformServer* to be created.
{provide: ALLOW_MULTIPLE_PLATFORMS, useValue: true},
];
function initDominoAdapter(injector: Injector) {
@@ -113,6 +110,13 @@ function _document(injector: Injector) {
}
/**
* Creates a server-side instance of an Angular platform.
*
* This platform should be used when performing server-side rendering of an Angular application.
* Standalone applications can be bootstrapped on the server using the `bootstrapApplication`
* function from `@angular/platform-browser`. When using `bootstrapApplication`, the `platformServer`
* should be created first and passed to the bootstrap function using the `BootstrapContext`.
*
* @publicApi
*/
export function platformServer(extraProviders?: StaticProvider[] | undefined): PlatformRef {
+19 -8
View File
@@ -22,9 +22,10 @@ import {
ɵstartMeasuring as startMeasuring,
ɵstopMeasuring as stopMeasuring,
} from '@angular/core';
import {BootstrapContext} from '@angular/platform-browser';
import {PlatformState} from './platform_state';
import {platformServer} from './server';
import {PlatformState} from './platform_state';
import {BEFORE_APP_SERIALIZED, INITIAL_CONFIG} from './tokens';
import {createScript} from './transfer_state';
@@ -291,14 +292,24 @@ export async function renderModule<T>(
/**
* Bootstraps an instance of an Angular application and renders it to a string.
*
* @usageNotes
*
* ```ts
* const bootstrap = () => bootstrapApplication(RootComponent, appConfig);
* const output: string = await renderApplication(bootstrap);
* import { BootstrapContext, bootstrapApplication } from '@angular/platform-browser';
* import { renderApplication } from '@angular/platform-server';
* import { ApplicationConfig } from '@angular/core';
* import { AppComponent } from './app.component';
*
* const appConfig: ApplicationConfig = { providers: [...] };
* const bootstrap = (context: BootstrapContext) =>
* bootstrapApplication(AppComponent, config, context);
* const output = await renderApplication(bootstrap);
* ```
*
* @param bootstrap A method that when invoked returns a promise that returns an `ApplicationRef`
* instance once resolved.
* instance once resolved. The method is invoked with an `Injector` instance that
* provides access to the platform-level dependency injection context.
* @param options Additional configuration for the render operation:
* - `document` - the document of the page to render, either as an HTML string or
* as a reference to the `document` instance.
@@ -309,8 +320,8 @@ export async function renderModule<T>(
*
* @publicApi
*/
export async function renderApplication<T>(
bootstrap: () => Promise<ApplicationRef>,
export async function renderApplication(
bootstrap: (context: BootstrapContext) => Promise<ApplicationRef>,
options: {document?: string | Document; url?: string; platformProviders?: Provider[]},
): Promise<string> {
const renderAppLabel = 'renderApplication';
@@ -321,7 +332,7 @@ export async function renderApplication<T>(
const platformRef = createServerPlatform(options);
try {
startMeasuring(bootstrapLabel);
const applicationRef = await bootstrap();
const applicationRef = await bootstrap({platformRef});
stopMeasuring(bootstrapLabel);
startMeasuring(_renderLabel);
@@ -20,6 +20,7 @@ import {
} from '@angular/core';
import {
bootstrapApplication,
BootstrapContext,
HydrationFeature,
provideClientHydration,
HydrationFeatureKind,
@@ -263,7 +264,8 @@ export async function ssr(
enableHydration ? provideClientHydration(...hydrationFeatures()) : [],
];
const bootstrap = () => bootstrapApplication(component, {providers});
const bootstrap = (context: BootstrapContext) =>
bootstrapApplication(component, {providers}, context);
return await renderApplication(bootstrap, {
document: options?.doc ?? defaultHtml,
@@ -49,6 +49,7 @@ import {
import {TestBed} from '@angular/core/testing';
import {
bootstrapApplication,
BootstrapContext,
BrowserModule,
provideClientHydration,
Title,
@@ -75,8 +76,9 @@ const APP_CONFIG: ApplicationConfig = {
function getStandaloneBootstrapFn(
component: Type<unknown>,
providers: Array<Provider | EnvironmentProviders> = [],
): () => Promise<ApplicationRef> {
return () => bootstrapApplication(component, mergeApplicationConfig(APP_CONFIG, {providers}));
): (context: BootstrapContext) => Promise<ApplicationRef> {
return (context: BootstrapContext) =>
bootstrapApplication(component, mergeApplicationConfig(APP_CONFIG, {providers}), context);
}
function createMyServerApp(standalone: boolean) {
+76 -96
View File
@@ -16,7 +16,7 @@ importers:
dependencies:
'@angular-devkit/build-angular':
specifier: 19.2.0-next.2
version: 19.2.0-next.2(@angular/compiler-cli@19.2.13)(@angular/compiler@19.2.13)(@angular/ssr@19.2.0-next.2)(@types/node@18.19.84)(chokidar@4.0.3)(karma@6.4.4)(protractor@7.0.0)(tsx@4.19.3)(typescript@5.8.2)(vite@6.1.0)
version: 19.2.0-next.2(@angular/compiler-cli@19.2.14)(@angular/compiler@19.2.14)(@angular/ssr@19.2.0-next.2)(@types/node@18.19.84)(chokidar@4.0.3)(karma@6.4.4)(protractor@7.0.0)(tsx@4.19.3)(typescript@5.8.2)(vite@6.1.0)
'@angular-devkit/core':
specifier: 19.2.0-next.2
version: 19.2.0-next.2(chokidar@4.0.3)
@@ -25,19 +25,19 @@ importers:
version: 19.2.0-next.2(chokidar@4.0.3)
'@angular/build':
specifier: 19.2.0-next.2
version: 19.2.0-next.2(@angular/compiler-cli@19.2.13)(@angular/compiler@19.2.13)(@angular/ssr@19.2.0-next.2)(@types/node@18.19.84)(chokidar@4.0.3)(less@4.2.2)(postcss@8.5.2)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)
version: 19.2.0-next.2(@angular/compiler-cli@19.2.14)(@angular/compiler@19.2.14)(@angular/ssr@19.2.0-next.2)(@types/node@18.19.84)(chokidar@4.0.3)(less@4.2.2)(postcss@8.5.2)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2)
'@angular/cdk':
specifier: 19.2.0-next.4
version: 19.2.0-next.4(@angular/common@19.2.13)(@angular/core@19.2.11)(rxjs@7.8.2)
version: 19.2.0-next.4(@angular/core@19.2.11)(rxjs@7.8.2)
'@angular/cli':
specifier: 19.2.0-next.2
version: 19.2.0-next.2(@types/node@18.19.84)(chokidar@4.0.3)
'@angular/material':
specifier: 19.2.0-next.4
version: 19.2.0-next.4(@angular/cdk@19.2.0-next.4)(@angular/common@19.2.13)(@angular/core@19.2.11)(@angular/forms@19.2.13)(@angular/platform-browser@19.2.13)(rxjs@7.8.2)
version: 19.2.0-next.4(@angular/cdk@19.2.0-next.4)(@angular/core@19.2.11)(@angular/forms@20.2.4)(@angular/platform-browser@20.2.4)(rxjs@7.8.2)
'@angular/ssr':
specifier: 19.2.0-next.2
version: 19.2.0-next.2(@angular/common@19.2.13)(@angular/core@19.2.11)(@angular/router@19.2.13)
version: 19.2.0-next.2(@angular/core@19.2.11)(@angular/router@19.2.14)
'@babel/cli':
specifier: 7.26.4
version: 7.26.4(@babel/core@7.26.9)
@@ -250,10 +250,10 @@ importers:
version: 2.0.1
ngx-flamegraph:
specifier: 0.0.12
version: 0.0.12(@angular/common@19.2.13)(@angular/core@19.2.11)
version: 0.0.12(@angular/core@19.2.11)
ngx-progressbar:
specifier: ^14.0.0
version: 14.0.0(@angular/cdk@19.2.0-next.4)(@angular/common@19.2.13)(@angular/core@19.2.11)(rxjs@7.8.2)
version: 14.0.0(@angular/cdk@19.2.0-next.4)(@angular/core@19.2.11)(rxjs@7.8.2)
open-in-idx:
specifier: ^0.1.1
version: 0.1.1
@@ -347,10 +347,10 @@ importers:
version: 0.1902.0-next.2(chokidar@4.0.3)
'@angular/animations':
specifier: ^19.2.0-next
version: 19.2.11(@angular/common@19.2.13)(@angular/core@19.2.11)
version: 19.2.11(@angular/core@19.2.11)
'@angular/build-tooling':
specifier: https://github.com/angular/dev-infra-private-build-tooling-builds.git#5db176c0f3211663830fd3ff4064c1dff0eaccb4
version: github.com/angular/dev-infra-private-build-tooling-builds/5db176c0f3211663830fd3ff4064c1dff0eaccb4(@angular/compiler-cli@19.2.13)(@angular/compiler@19.2.13)(@angular/ssr@19.2.0-next.2)(chokidar@4.0.3)(karma-chrome-launcher@3.2.0)(karma-firefox-launcher@2.1.3)(karma-jasmine@5.1.0)(karma-junit-reporter@2.0.1)(karma-requirejs@1.1.0)(karma-sourcemap-loader@0.4.0)(karma@6.4.4)(less@4.2.2)(postcss@8.5.2)(rxjs@7.8.2)(terser@5.39.0)(tsx@4.19.3)
version: github.com/angular/dev-infra-private-build-tooling-builds/5db176c0f3211663830fd3ff4064c1dff0eaccb4(@angular/compiler-cli@19.2.14)(@angular/compiler@19.2.14)(@angular/ssr@19.2.0-next.2)(chokidar@4.0.3)(karma-chrome-launcher@3.2.0)(karma-firefox-launcher@2.1.3)(karma-jasmine@5.1.0)(karma-junit-reporter@2.0.1)(karma-requirejs@1.1.0)(karma-sourcemap-loader@0.4.0)(karma@6.4.4)(less@4.2.2)(postcss@8.5.2)(rxjs@7.8.2)(terser@5.39.0)(tsx@4.19.3)
'@angular/core':
specifier: ^19.2.0-next
version: 19.2.11(rxjs@7.8.2)
@@ -452,7 +452,7 @@ importers:
version: 0.5.16
angular-split:
specifier: ^19.0.0
version: 19.0.0(@angular/common@19.2.13)(@angular/core@19.2.11)(rxjs@7.8.2)
version: 19.0.0(@angular/core@19.2.11)(rxjs@7.8.2)
check-side-effects:
specifier: 0.0.23
version: 0.0.23
@@ -800,7 +800,7 @@ packages:
transitivePeerDependencies:
- chokidar
/@angular-devkit/build-angular@19.2.0-next.2(@angular/compiler-cli@19.2.13)(@angular/compiler@19.2.13)(@angular/ssr@19.2.0-next.2)(@types/node@18.19.84)(chokidar@4.0.3)(karma@6.4.4)(protractor@7.0.0)(tsx@4.19.3)(typescript@5.8.2)(vite@6.1.0):
/@angular-devkit/build-angular@19.2.0-next.2(@angular/compiler-cli@19.2.14)(@angular/compiler@19.2.14)(@angular/ssr@19.2.0-next.2)(@types/node@18.19.84)(chokidar@4.0.3)(karma@6.4.4)(protractor@7.0.0)(tsx@4.19.3)(typescript@5.8.2)(vite@6.1.0):
resolution: {integrity: sha512-o3/X02x4p9pCVaPB4uoc2VUL2s2YvGW58jfSHRhwtiLVoIgpnbyHyyhtIdO8rLRr09Pk1fLUvXVY4/d6hjXt1Q==, tarball: https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-19.2.0-next.2.tgz}
engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'}
peerDependencies:
@@ -848,9 +848,9 @@ packages:
'@angular-devkit/architect': 0.1902.0-next.2(chokidar@4.0.3)
'@angular-devkit/build-webpack': 0.1902.0-next.2(chokidar@4.0.3)(webpack-dev-server@5.2.0)(webpack@5.97.1)
'@angular-devkit/core': 19.2.0-next.2(chokidar@4.0.3)
'@angular/build': 19.2.0-next.2(@angular/compiler-cli@19.2.13)(@angular/compiler@19.2.13)(@angular/ssr@19.2.0-next.2)(@types/node@18.19.84)(chokidar@4.0.3)(less@4.2.2)(postcss@8.5.2)(terser@5.38.2)(tsx@4.19.3)(typescript@5.8.2)
'@angular/compiler-cli': 19.2.13(@angular/compiler@19.2.13)(typescript@5.8.2)
'@angular/ssr': 19.2.0-next.2(@angular/common@19.2.13)(@angular/core@19.2.11)(@angular/router@19.2.13)
'@angular/build': 19.2.0-next.2(@angular/compiler-cli@19.2.14)(@angular/compiler@19.2.14)(@angular/ssr@19.2.0-next.2)(@types/node@18.19.84)(chokidar@4.0.3)(less@4.2.2)(postcss@8.5.2)(terser@5.38.2)(tsx@4.19.3)(typescript@5.8.2)
'@angular/compiler-cli': 19.2.14(@angular/compiler@19.2.14)(typescript@5.8.2)
'@angular/ssr': 19.2.0-next.2(@angular/core@19.2.11)(@angular/router@19.2.14)
'@babel/core': 7.26.8
'@babel/generator': 7.26.8
'@babel/helper-annotate-as-pure': 7.25.9
@@ -861,7 +861,7 @@ packages:
'@babel/preset-env': 7.26.8(@babel/core@7.26.8)
'@babel/runtime': 7.26.7
'@discoveryjs/json-ext': 0.6.3
'@ngtools/webpack': 19.2.0-next.2(@angular/compiler-cli@19.2.13)(typescript@5.8.2)(webpack@5.97.1)
'@ngtools/webpack': 19.2.0-next.2(@angular/compiler-cli@19.2.14)(typescript@5.8.2)(webpack@5.97.1)
'@vitejs/plugin-basic-ssl': 1.2.0(vite@6.1.0)
ansi-colors: 4.1.3
autoprefixer: 10.4.20(postcss@8.5.2)
@@ -1004,14 +1004,13 @@ packages:
- chokidar
dev: false
/@angular/animations@19.2.11(@angular/common@19.2.13)(@angular/core@19.2.11):
/@angular/animations@19.2.11(@angular/core@19.2.11):
resolution: {integrity: sha512-NR33bZVho7EgTc1fmCnmkwc2/U266n311Wfvk7VVtz+0Q9WliNdDLBon654V8IWSKvlqKXyU3W+fp0VjH/FvSw==, tarball: https://registry.npmjs.org/@angular/animations/-/animations-19.2.11.tgz}
engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0}
peerDependencies:
'@angular/common': 19.2.11
'@angular/core': 19.2.11
dependencies:
'@angular/common': 19.2.13(@angular/core@19.2.11)(rxjs@7.8.2)
'@angular/core': 19.2.11(rxjs@7.8.2)
tslib: 2.8.1
@@ -1025,7 +1024,7 @@ packages:
- zone.js
dev: true
/@angular/build@19.1.0-rc.0(@angular/compiler-cli@19.2.13)(@angular/compiler@19.2.13)(@angular/ssr@19.2.0-next.2)(@types/node@18.19.84)(chokidar@4.0.3)(less@4.2.2)(postcss@8.5.2)(terser@5.39.0)(tsx@4.19.3)(typescript@5.7.3):
/@angular/build@19.1.0-rc.0(@angular/compiler-cli@19.2.14)(@angular/compiler@19.2.14)(@angular/ssr@19.2.0-next.2)(@types/node@18.19.84)(chokidar@4.0.3)(less@4.2.2)(postcss@8.5.2)(terser@5.39.0)(tsx@4.19.3)(typescript@5.7.3):
resolution: {integrity: sha512-ALl+MVMYBF+E7HyAQ+1MtE6sNIOAX0o2Sfs0wdIQfM2unRl6jPsz/Ker4BjnNQIK4wRCcstyzBv5mZBDulfFIQ==, tarball: https://registry.npmjs.org/@angular/build/-/build-19.1.0-rc.0.tgz}
engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'}
peerDependencies:
@@ -1060,9 +1059,9 @@ packages:
dependencies:
'@ampproject/remapping': 2.3.0
'@angular-devkit/architect': 0.1901.0-rc.0(chokidar@4.0.3)
'@angular/compiler': 19.2.13
'@angular/compiler-cli': 19.2.13(@angular/compiler@19.2.13)(typescript@5.8.2)
'@angular/ssr': 19.2.0-next.2(@angular/common@19.2.13)(@angular/core@19.2.11)(@angular/router@19.2.13)
'@angular/compiler': 19.2.14
'@angular/compiler-cli': 19.2.14(@angular/compiler@19.2.14)(typescript@5.8.2)
'@angular/ssr': 19.2.0-next.2(@angular/core@19.2.11)(@angular/router@19.2.14)
'@babel/core': 7.26.0
'@babel/helper-annotate-as-pure': 7.25.9
'@babel/helper-split-export-declaration': 7.24.7
@@ -1105,7 +1104,7 @@ packages:
- yaml
dev: true
/@angular/build@19.2.0-next.2(@angular/compiler-cli@19.2.13)(@angular/compiler@19.2.13)(@angular/ssr@19.2.0-next.2)(@types/node@18.19.84)(chokidar@4.0.3)(less@4.2.2)(postcss@8.5.2)(terser@5.38.2)(tsx@4.19.3)(typescript@5.8.2):
/@angular/build@19.2.0-next.2(@angular/compiler-cli@19.2.14)(@angular/compiler@19.2.14)(@angular/ssr@19.2.0-next.2)(@types/node@18.19.84)(chokidar@4.0.3)(less@4.2.2)(postcss@8.5.2)(terser@5.38.2)(tsx@4.19.3)(typescript@5.8.2):
resolution: {integrity: sha512-FmpJla0+M+BE1bQbHIKbl5wKrHsSg6JTIl+kiW/kW4GKKZsS4FJkg56UhyI7+bjuId9s3wptpdMIFpRDaDytRg==, tarball: https://registry.npmjs.org/@angular/build/-/build-19.2.0-next.2.tgz}
engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'}
peerDependencies:
@@ -1140,9 +1139,9 @@ packages:
dependencies:
'@ampproject/remapping': 2.3.0
'@angular-devkit/architect': 0.1902.0-next.2(chokidar@4.0.3)
'@angular/compiler': 19.2.13
'@angular/compiler-cli': 19.2.13(@angular/compiler@19.2.13)(typescript@5.8.2)
'@angular/ssr': 19.2.0-next.2(@angular/common@19.2.13)(@angular/core@19.2.11)(@angular/router@19.2.13)
'@angular/compiler': 19.2.14
'@angular/compiler-cli': 19.2.14(@angular/compiler@19.2.14)(typescript@5.8.2)
'@angular/ssr': 19.2.0-next.2(@angular/core@19.2.11)(@angular/router@19.2.14)
'@babel/core': 7.26.8
'@babel/helper-annotate-as-pure': 7.25.9
'@babel/helper-split-export-declaration': 7.24.7
@@ -1185,7 +1184,7 @@ packages:
- yaml
dev: false
/@angular/build@19.2.0-next.2(@angular/compiler-cli@19.2.13)(@angular/compiler@19.2.13)(@angular/ssr@19.2.0-next.2)(@types/node@18.19.84)(chokidar@4.0.3)(less@4.2.2)(postcss@8.5.2)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2):
/@angular/build@19.2.0-next.2(@angular/compiler-cli@19.2.14)(@angular/compiler@19.2.14)(@angular/ssr@19.2.0-next.2)(@types/node@18.19.84)(chokidar@4.0.3)(less@4.2.2)(postcss@8.5.2)(terser@5.39.0)(tsx@4.19.3)(typescript@5.8.2):
resolution: {integrity: sha512-FmpJla0+M+BE1bQbHIKbl5wKrHsSg6JTIl+kiW/kW4GKKZsS4FJkg56UhyI7+bjuId9s3wptpdMIFpRDaDytRg==, tarball: https://registry.npmjs.org/@angular/build/-/build-19.2.0-next.2.tgz}
engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'}
peerDependencies:
@@ -1220,9 +1219,9 @@ packages:
dependencies:
'@ampproject/remapping': 2.3.0
'@angular-devkit/architect': 0.1902.0-next.2(chokidar@4.0.3)
'@angular/compiler': 19.2.13
'@angular/compiler-cli': 19.2.13(@angular/compiler@19.2.13)(typescript@5.8.2)
'@angular/ssr': 19.2.0-next.2(@angular/common@19.2.13)(@angular/core@19.2.11)(@angular/router@19.2.13)
'@angular/compiler': 19.2.14
'@angular/compiler-cli': 19.2.14(@angular/compiler@19.2.14)(typescript@5.8.2)
'@angular/ssr': 19.2.0-next.2(@angular/core@19.2.11)(@angular/router@19.2.14)
'@babel/core': 7.26.8
'@babel/helper-annotate-as-pure': 7.25.9
'@babel/helper-split-export-declaration': 7.24.7
@@ -1265,14 +1264,13 @@ packages:
- yaml
dev: false
/@angular/cdk@19.2.0-next.4(@angular/common@19.2.13)(@angular/core@19.2.11)(rxjs@7.8.2):
/@angular/cdk@19.2.0-next.4(@angular/core@19.2.11)(rxjs@7.8.2):
resolution: {integrity: sha512-fmmwokyT2IGLRGzQEj2j4EoQBNdML+QYKyH3J3KlGN7i3p3G63uitzrvz5sEAdsXnpebxemhAs9aPW+HPhsvew==, tarball: https://registry.npmjs.org/@angular/cdk/-/cdk-19.2.0-next.4.tgz}
peerDependencies:
'@angular/common': ^19.0.0-0 || ^19.1.0-0 || ^19.2.0-0 || ^19.3.0-0 || ^20.0.0-0
'@angular/core': ^19.0.0-0 || ^19.1.0-0 || ^19.2.0-0 || ^19.3.0-0 || ^20.0.0-0
rxjs: ^6.5.3 || ^7.4.0
dependencies:
'@angular/common': 19.2.13(@angular/core@19.2.11)(rxjs@7.8.2)
'@angular/core': 19.2.11(rxjs@7.8.2)
rxjs: 7.8.2
tslib: 2.8.1
@@ -1308,26 +1306,15 @@ packages:
- supports-color
dev: false
/@angular/common@19.2.13(@angular/core@19.2.11)(rxjs@7.8.2):
resolution: {integrity: sha512-k7I4bLH+bgI02VL81MaL0NcZPfVl153KAiARwk+ZlkmQjMnWlmsAHQ6054SWoNEXwP855ATR6YYDVqJh8TZaqw==, tarball: https://registry.npmjs.org/@angular/common/-/common-19.2.13.tgz}
engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0}
peerDependencies:
'@angular/core': 19.2.13
rxjs: ^6.5.3 || ^7.4.0
dependencies:
'@angular/core': 19.2.11(rxjs@7.8.2)
rxjs: 7.8.2
tslib: 2.8.1
/@angular/compiler-cli@19.2.13(@angular/compiler@19.2.13)(typescript@5.8.2):
resolution: {integrity: sha512-SSuzKMcktvd6VexivDwhP7ctQBD6yyoo5E91I7Frn5nrvYNM+TIyYcXmJ4dgby5/GrPZGfm2sWl3ARr2vbCgtA==, tarball: https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-19.2.13.tgz}
/@angular/compiler-cli@19.2.14(@angular/compiler@19.2.14)(typescript@5.8.2):
resolution: {integrity: sha512-e9/h86ETjoIK2yTLE9aUeMCKujdg/du2pq7run/aINjop4RtnNOw+ZlSTUa6R65lP5CVwDup1kPytpAoifw8cA==, tarball: https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-19.2.14.tgz}
engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0}
hasBin: true
peerDependencies:
'@angular/compiler': 19.2.13
'@angular/compiler': 19.2.14
typescript: '>=5.5 <5.9'
dependencies:
'@angular/compiler': 19.2.13
'@angular/compiler': 19.2.14
'@babel/core': 7.26.9
'@jridgewell/sourcemap-codec': 1.5.0
chokidar: 4.0.3
@@ -1340,8 +1327,8 @@ packages:
transitivePeerDependencies:
- supports-color
/@angular/compiler@19.2.13:
resolution: {integrity: sha512-xAj1peVrQtb65NsULmz8ocH4QZ4ESG5YiiVzJ0tLz8t280xY+QhJiM6C0+jaCVHLXvZp0c7GEzsYjL6x1HmabQ==, tarball: https://registry.npmjs.org/@angular/compiler/-/compiler-19.2.13.tgz}
/@angular/compiler@19.2.14:
resolution: {integrity: sha512-ZqJDYOdhgKpVGNq3+n/Gbxma8DVYElDsoRe0tvNtjkWBVdaOxdZZUqmJ3kdCBsqD/aqTRvRBu0KGo9s2fCChkA==, tarball: https://registry.npmjs.org/@angular/compiler/-/compiler-19.2.14.tgz}
engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0}
dependencies:
tslib: 2.8.1
@@ -1367,23 +1354,22 @@ packages:
rxjs: 7.8.2
tslib: 2.8.1
/@angular/forms@19.2.13(@angular/common@19.2.13)(@angular/core@19.2.11)(@angular/platform-browser@19.2.13)(rxjs@7.8.2):
resolution: {integrity: sha512-g46KQFrBJhmknczlGEYvWVsPhk7ZI8WOuWkzWEl81Lf3ojEVA/OF8w4VwKZL7wOMKRxOUhuYq6tNPm8tBjtryw==, tarball: https://registry.npmjs.org/@angular/forms/-/forms-19.2.13.tgz}
engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0}
/@angular/forms@20.2.4(@angular/core@19.2.11)(@angular/platform-browser@20.2.4)(rxjs@7.8.2):
resolution: {integrity: sha512-wbgnW+GALVAmK6hgFegkwlHKw35onvh9Z5A236HCyUySEAOiaD/3CoDg5Hw4iHQAiSU6Fn2NwDiv+W0xki6WDw==, tarball: https://registry.npmjs.org/@angular/forms/-/forms-20.2.4.tgz}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
peerDependencies:
'@angular/common': 19.2.13
'@angular/core': 19.2.13
'@angular/platform-browser': 19.2.13
'@angular/common': 20.2.4
'@angular/core': 20.2.4
'@angular/platform-browser': 20.2.4
rxjs: ^6.5.3 || ^7.4.0
dependencies:
'@angular/common': 19.2.13(@angular/core@19.2.11)(rxjs@7.8.2)
'@angular/core': 19.2.11(rxjs@7.8.2)
'@angular/platform-browser': 19.2.13(@angular/animations@19.2.11)(@angular/common@19.2.13)(@angular/core@19.2.11)
'@angular/platform-browser': 20.2.4(@angular/animations@19.2.11)(@angular/core@19.2.11)
rxjs: 7.8.2
tslib: 2.8.1
dev: false
/@angular/material@19.2.0-next.4(@angular/cdk@19.2.0-next.4)(@angular/common@19.2.13)(@angular/core@19.2.11)(@angular/forms@19.2.13)(@angular/platform-browser@19.2.13)(rxjs@7.8.2):
/@angular/material@19.2.0-next.4(@angular/cdk@19.2.0-next.4)(@angular/core@19.2.11)(@angular/forms@20.2.4)(@angular/platform-browser@20.2.4)(rxjs@7.8.2):
resolution: {integrity: sha512-darSa77CFdlVFax88GLNJWstHJp8j5qUo/kbQwUNsN0ltigS4o7eaczBA9ukekoSpXSgijq6y2VfnkkYi8hCZQ==, tarball: https://registry.npmjs.org/@angular/material/-/material-19.2.0-next.4.tgz}
peerDependencies:
'@angular/cdk': 19.2.0-next.4
@@ -1393,47 +1379,44 @@ packages:
'@angular/platform-browser': ^19.0.0-0 || ^19.1.0-0 || ^19.2.0-0 || ^19.3.0-0 || ^20.0.0-0
rxjs: ^6.5.3 || ^7.4.0
dependencies:
'@angular/cdk': 19.2.0-next.4(@angular/common@19.2.13)(@angular/core@19.2.11)(rxjs@7.8.2)
'@angular/common': 19.2.13(@angular/core@19.2.11)(rxjs@7.8.2)
'@angular/cdk': 19.2.0-next.4(@angular/core@19.2.11)(rxjs@7.8.2)
'@angular/core': 19.2.11(rxjs@7.8.2)
'@angular/forms': 19.2.13(@angular/common@19.2.13)(@angular/core@19.2.11)(@angular/platform-browser@19.2.13)(rxjs@7.8.2)
'@angular/platform-browser': 19.2.13(@angular/animations@19.2.11)(@angular/common@19.2.13)(@angular/core@19.2.11)
'@angular/forms': 20.2.4(@angular/core@19.2.11)(@angular/platform-browser@20.2.4)(rxjs@7.8.2)
'@angular/platform-browser': 20.2.4(@angular/animations@19.2.11)(@angular/core@19.2.11)
rxjs: 7.8.2
tslib: 2.8.1
dev: false
/@angular/platform-browser@19.2.13(@angular/animations@19.2.11)(@angular/common@19.2.13)(@angular/core@19.2.11):
resolution: {integrity: sha512-YeuRfGbo8qFepoAUoubk/1079wOown5Qgr9eAhgCXxoXb2rt87xbJF3YCSSim38SP3kK1rJQqP+Sr8n7ef+n5Q==, tarball: https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-19.2.13.tgz}
engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0}
/@angular/platform-browser@20.2.4(@angular/animations@19.2.11)(@angular/core@19.2.11):
resolution: {integrity: sha512-81vzW8xhnJU7AiYJKXLR2MuvawzhRDgwyNkPEep58wty5zNuIUCXdUERJSsXo7m/U2Dg1FUFfqLm4RC2UkqLzA==, tarball: https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-20.2.4.tgz}
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
peerDependencies:
'@angular/animations': 19.2.13
'@angular/common': 19.2.13
'@angular/core': 19.2.13
'@angular/animations': 20.2.4
'@angular/common': 20.2.4
'@angular/core': 20.2.4
peerDependenciesMeta:
'@angular/animations':
optional: true
dependencies:
'@angular/animations': 19.2.11(@angular/common@19.2.13)(@angular/core@19.2.11)
'@angular/common': 19.2.13(@angular/core@19.2.11)(rxjs@7.8.2)
'@angular/animations': 19.2.11(@angular/core@19.2.11)
'@angular/core': 19.2.11(rxjs@7.8.2)
tslib: 2.8.1
/@angular/router@19.2.13(@angular/common@19.2.13)(@angular/core@19.2.11)(@angular/platform-browser@19.2.13)(rxjs@7.8.2):
resolution: {integrity: sha512-BZObWQtGkDv2WHyLVRRecGbLwalbI8kOXKaVgN5dqP4z/t5bpzYXZixPO9e0E1Ff0+m4tQalhTc84j8X7XZuTw==, tarball: https://registry.npmjs.org/@angular/router/-/router-19.2.13.tgz}
/@angular/router@19.2.14(@angular/core@19.2.11)(@angular/platform-browser@20.2.4)(rxjs@7.8.2):
resolution: {integrity: sha512-cBTWY9Jx7YhbmDYDb7Hqz4Q7UNIMlKTkdKToJd2pbhIXyoS+kHVQrySmyca+jgvYMjWnIjsAEa3dpje12D4mFw==, tarball: https://registry.npmjs.org/@angular/router/-/router-19.2.14.tgz}
engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0}
peerDependencies:
'@angular/common': 19.2.13
'@angular/core': 19.2.13
'@angular/platform-browser': 19.2.13
'@angular/common': 19.2.14
'@angular/core': 19.2.14
'@angular/platform-browser': 19.2.14
rxjs: ^6.5.3 || ^7.4.0
dependencies:
'@angular/common': 19.2.13(@angular/core@19.2.11)(rxjs@7.8.2)
'@angular/core': 19.2.11(rxjs@7.8.2)
'@angular/platform-browser': 19.2.13(@angular/animations@19.2.11)(@angular/common@19.2.13)(@angular/core@19.2.11)
'@angular/platform-browser': 20.2.4(@angular/animations@19.2.11)(@angular/core@19.2.11)
rxjs: 7.8.2
tslib: 2.8.1
/@angular/ssr@19.2.0-next.2(@angular/common@19.2.13)(@angular/core@19.2.11)(@angular/router@19.2.13):
/@angular/ssr@19.2.0-next.2(@angular/core@19.2.11)(@angular/router@19.2.14):
resolution: {integrity: sha512-JN5Utru8xJRpCF+ArG3CCgzlCYgbnB2XUV4J6uO56KgdqK5OeCOCcsuJYBHu+ifaF4ecb74JdXWm0VgB/HQKXA==, tarball: https://registry.npmjs.org/@angular/ssr/-/ssr-19.2.0-next.2.tgz}
peerDependencies:
'@angular/common': ^19.0.0 || ^19.2.0-next.0
@@ -1444,9 +1427,8 @@ packages:
'@angular/platform-server':
optional: true
dependencies:
'@angular/common': 19.2.13(@angular/core@19.2.11)(rxjs@7.8.2)
'@angular/core': 19.2.11(rxjs@7.8.2)
'@angular/router': 19.2.13(@angular/common@19.2.13)(@angular/core@19.2.11)(@angular/platform-browser@19.2.13)(rxjs@7.8.2)
'@angular/router': 19.2.14(@angular/core@19.2.11)(@angular/platform-browser@20.2.4)(rxjs@7.8.2)
tslib: 2.8.1
/@antfu/install-pkg@1.0.0:
@@ -3826,7 +3808,7 @@ packages:
lodash.snakecase: 4.1.1
merge-stream: 2.0.0
p-queue: 6.6.2
protobufjs: 7.4.0
protobufjs: 7.5.2
retry-request: 7.0.2(supports-color@10.0.0)
split-array-stream: 2.0.0
stack-trace: 0.0.10
@@ -3863,7 +3845,7 @@ packages:
dependencies:
lodash.camelcase: 4.3.0
long: 5.3.1
protobufjs: 7.4.0
protobufjs: 7.5.2
yargs: 17.7.2
dev: true
@@ -4653,7 +4635,7 @@ packages:
'@napi-rs/nice-win32-x64-msvc': 1.0.1
optional: true
/@ngtools/webpack@19.2.0-next.2(@angular/compiler-cli@19.2.13)(typescript@5.8.2)(webpack@5.97.1):
/@ngtools/webpack@19.2.0-next.2(@angular/compiler-cli@19.2.14)(typescript@5.8.2)(webpack@5.97.1):
resolution: {integrity: sha512-YxtR1+YiXjOmaunOIt3CpmEQunV42pbG5pYd/l6Pjqg/83MHxO8h2ax51By/LIzKm6P1qKsGTEtyZBanG7JgGQ==, tarball: https://registry.npmjs.org/@ngtools/webpack/-/webpack-19.2.0-next.2.tgz}
engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'}
peerDependencies:
@@ -4661,7 +4643,7 @@ packages:
typescript: '>=5.5 <5.8'
webpack: ^5.54.0
dependencies:
'@angular/compiler-cli': 19.2.13(@angular/compiler@19.2.13)(typescript@5.8.2)
'@angular/compiler-cli': 19.2.14(@angular/compiler@19.2.14)(typescript@5.8.2)
typescript: 5.8.2
webpack: 5.97.1(esbuild@0.25.0)
dev: false
@@ -7179,14 +7161,13 @@ packages:
resolution: {integrity: sha512-vqsT6zwu80cZ8RY7qRQBZuy6Fq5X7/N5hkV9LzNT0c8b546rw4ErGK6muW1u2JnDKYa7+jJuaGM702bWir4HGw==, tarball: https://registry.npmjs.org/angular-mocks/-/angular-mocks-1.8.3.tgz}
dev: false
/angular-split@19.0.0(@angular/common@19.2.13)(@angular/core@19.2.11)(rxjs@7.8.2):
/angular-split@19.0.0(@angular/core@19.2.11)(rxjs@7.8.2):
resolution: {integrity: sha512-vQqXWLcCimFmInu2lpGKIfS9FtYBgKmoWenPjeYkHSRdWmb7HLGlQoNPj1oALrwdhIWFPdySgp0BIXDe2IAepQ==, tarball: https://registry.npmjs.org/angular-split/-/angular-split-19.0.0.tgz}
peerDependencies:
'@angular/common': '>=19.0.0'
'@angular/core': '>=19.0.0'
rxjs: '>=7.0.0'
dependencies:
'@angular/common': 19.2.13(@angular/core@19.2.11)(rxjs@7.8.2)
'@angular/core': 19.2.11(rxjs@7.8.2)
rxjs: 7.8.2
tslib: 2.8.1
@@ -11435,7 +11416,7 @@ packages:
node-fetch: 2.7.0
object-hash: 3.0.0
proto3-json-serializer: 2.0.2
protobufjs: 7.4.0
protobufjs: 7.5.2
retry-request: 7.0.2(supports-color@10.0.0)
uuid: 9.0.1
transitivePeerDependencies:
@@ -14329,18 +14310,17 @@ packages:
engines: {node: '>= 0.4.0'}
dev: true
/ngx-flamegraph@0.0.12(@angular/common@19.2.13)(@angular/core@19.2.11):
/ngx-flamegraph@0.0.12(@angular/core@19.2.11):
resolution: {integrity: sha512-YoxrqlL36Bg5Ca9fu10kuSUmaWHAvx7jkxINF4/4cXn9bBPRfu78FqnZ5LIULC0+iScZcSDSWDAnUdn8H7+wGw==, tarball: https://registry.npmjs.org/ngx-flamegraph/-/ngx-flamegraph-0.0.12.tgz}
peerDependencies:
'@angular/common': ^9.0.0
'@angular/core': ^9.0.0
dependencies:
'@angular/common': 19.2.13(@angular/core@19.2.11)(rxjs@7.8.2)
'@angular/core': 19.2.11(rxjs@7.8.2)
tslib: 2.8.1
dev: false
/ngx-progressbar@14.0.0(@angular/cdk@19.2.0-next.4)(@angular/common@19.2.13)(@angular/core@19.2.11)(rxjs@7.8.2):
/ngx-progressbar@14.0.0(@angular/cdk@19.2.0-next.4)(@angular/core@19.2.11)(rxjs@7.8.2):
resolution: {integrity: sha512-tDj7h5F2aSI4/XaJjs50FnELVe6qFqyz3vVq22acacd3oDW2EyJB4c+IYaxMf5972OdTw0WL4n6UwQ3dqC+gCA==, tarball: https://registry.npmjs.org/ngx-progressbar/-/ngx-progressbar-14.0.0.tgz}
peerDependencies:
'@angular/cdk': '>=17.3.0'
@@ -14348,8 +14328,7 @@ packages:
'@angular/core': '>=17.3.0'
rxjs: '>=7.0.0'
dependencies:
'@angular/cdk': 19.2.0-next.4(@angular/common@19.2.13)(@angular/core@19.2.11)(rxjs@7.8.2)
'@angular/common': 19.2.13(@angular/core@19.2.11)(rxjs@7.8.2)
'@angular/cdk': 19.2.0-next.4(@angular/core@19.2.11)(rxjs@7.8.2)
'@angular/core': 19.2.11(rxjs@7.8.2)
rxjs: 7.8.2
tslib: 2.8.1
@@ -15517,7 +15496,7 @@ packages:
resolution: {integrity: sha512-SAzp/O4Yh02jGdRc+uIrGoe87dkN/XtwxfZ4ZyafJHymd79ozp5VG5nyZ7ygqPM5+cpLDjjGnYFUkngonyDPOQ==, tarball: https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-2.0.2.tgz}
engines: {node: '>=14.0.0'}
dependencies:
protobufjs: 7.4.0
protobufjs: 7.5.2
dev: true
/protobufjs@6.8.8:
@@ -15538,8 +15517,8 @@ packages:
'@types/node': 10.17.60
long: 4.0.0
/protobufjs@7.4.0:
resolution: {integrity: sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==, tarball: https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz}
/protobufjs@7.5.2:
resolution: {integrity: sha512-f2ls6rpO6G153Cy+o2XQ+Y0sARLOZ17+OGVLHrc3VUKcLHYKEKWbkSujdBWQXM7gKn5NTfp0XnRPZn1MIu8n9w==, tarball: https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.2.tgz}
engines: {node: '>=12.0.0'}
dependencies:
'@protobufjs/aspromise': 1.1.2
@@ -15699,6 +15678,7 @@ packages:
/puppeteer@24.4.0(typescript@5.8.2):
resolution: {integrity: sha512-E4JhJzjS8AAI+6N/b+Utwarhz6zWl3+MR725fal+s3UlOlX2eWdsvYYU+Q5bXMjs9eZEGkNQroLkn7j11s2k1Q==, tarball: https://registry.npmjs.org/puppeteer/-/puppeteer-24.4.0.tgz}
engines: {node: '>=18'}
deprecated: < 24.10.2 is no longer supported
hasBin: true
dependencies:
'@puppeteer/browsers': 2.8.0
@@ -19777,14 +19757,14 @@ packages:
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==, tarball: https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz}
dev: true
github.com/angular/dev-infra-private-build-tooling-builds/5db176c0f3211663830fd3ff4064c1dff0eaccb4(@angular/compiler-cli@19.2.13)(@angular/compiler@19.2.13)(@angular/ssr@19.2.0-next.2)(chokidar@4.0.3)(karma-chrome-launcher@3.2.0)(karma-firefox-launcher@2.1.3)(karma-jasmine@5.1.0)(karma-junit-reporter@2.0.1)(karma-requirejs@1.1.0)(karma-sourcemap-loader@0.4.0)(karma@6.4.4)(less@4.2.2)(postcss@8.5.2)(rxjs@7.8.2)(terser@5.39.0)(tsx@4.19.3):
github.com/angular/dev-infra-private-build-tooling-builds/5db176c0f3211663830fd3ff4064c1dff0eaccb4(@angular/compiler-cli@19.2.14)(@angular/compiler@19.2.14)(@angular/ssr@19.2.0-next.2)(chokidar@4.0.3)(karma-chrome-launcher@3.2.0)(karma-firefox-launcher@2.1.3)(karma-jasmine@5.1.0)(karma-junit-reporter@2.0.1)(karma-requirejs@1.1.0)(karma-sourcemap-loader@0.4.0)(karma@6.4.4)(less@4.2.2)(postcss@8.5.2)(rxjs@7.8.2)(terser@5.39.0)(tsx@4.19.3):
resolution: {tarball: https://codeload.github.com/angular/dev-infra-private-build-tooling-builds/tar.gz/5db176c0f3211663830fd3ff4064c1dff0eaccb4}
id: github.com/angular/dev-infra-private-build-tooling-builds/5db176c0f3211663830fd3ff4064c1dff0eaccb4
name: '@angular/build-tooling'
version: 0.0.0-d44be7e28087c3499d70dda9859d51c1cd3fe1bf
dependencies:
'@angular/benchpress': 0.3.0(rxjs@7.8.2)
'@angular/build': 19.1.0-rc.0(@angular/compiler-cli@19.2.13)(@angular/compiler@19.2.13)(@angular/ssr@19.2.0-next.2)(@types/node@18.19.84)(chokidar@4.0.3)(less@4.2.2)(postcss@8.5.2)(terser@5.39.0)(tsx@4.19.3)(typescript@5.7.3)
'@angular/build': 19.1.0-rc.0(@angular/compiler-cli@19.2.14)(@angular/compiler@19.2.14)(@angular/ssr@19.2.0-next.2)(@types/node@18.19.84)(chokidar@4.0.3)(less@4.2.2)(postcss@8.5.2)(terser@5.39.0)(tsx@4.19.3)(typescript@5.7.3)
'@babel/core': 7.26.10
'@babel/plugin-proposal-async-generator-functions': 7.20.7(@babel/core@7.26.10)
'@bazel/buildifier': 6.3.3
@@ -0,0 +1,13 @@
diff --git a/node_modules/@angular/ssr/fesm2022/ssr.mjs b/node_modules/@angular/ssr/fesm2022/ssr.mjs
index 3267e86..1b628be 100755
--- a/node_modules/@angular/ssr/fesm2022/ssr.mjs
+++ b/node_modules/@angular/ssr/fesm2022/ssr.mjs
@@ -1093,7 +1093,7 @@ async function getRoutesFromAngularRouterConfig(bootstrap, document, url, invoke
applicationRef = moduleRef.injector.get(ApplicationRef);
}
else {
- applicationRef = await bootstrap();
+ applicationRef = await bootstrap({platformRef});
}
const injector = applicationRef.injector;
const router = injector.get(Router);