feat(platform-browser): add context to createApplication

This is necessary to use SSR safely with `createApplication` and avoid constraining users to `bootstrapApplication`. It is one more step towards feature parity between `createApplication` and `bootstrapApplication`.
This commit is contained in:
Doug Parker
2025-11-06 15:22:24 -08:00
committed by Andrew Kushnir
parent ab67988d2e
commit ec9dc94cee
3 changed files with 32 additions and 6 deletions
@@ -52,7 +52,7 @@ export class By {
}
// @public
export function createApplication(options?: ApplicationConfig): Promise<ApplicationRef>;
export function createApplication(options?: ApplicationConfig, context?: BootstrapContext): Promise<ApplicationRef>;
// @public
export function disableDebugTools(): void;
+11 -5
View File
@@ -131,8 +131,7 @@ export async function bootstrapApplication(
): Promise<ApplicationRef> {
const config = {
rootComponent,
platformRef: context?.platformRef,
...createProvidersConfig(options),
...createProvidersConfig(options, context),
};
if ((typeof ngJitMode === 'undefined' || ngJitMode) && typeof fetch === 'function') {
@@ -150,20 +149,27 @@ export async function bootstrapApplication(
*
* @param options Extra configuration for the application environment, 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
*/
export async function createApplication(options?: ApplicationConfig): Promise<ApplicationRef> {
export async function createApplication(
options?: ApplicationConfig,
context?: BootstrapContext,
): Promise<ApplicationRef> {
if ((typeof ngJitMode === 'undefined' || ngJitMode) && typeof fetch === 'function') {
await resolveJitResources();
}
return internalCreateApplication(createProvidersConfig(options));
return internalCreateApplication(createProvidersConfig(options, context));
}
function createProvidersConfig(options?: ApplicationConfig) {
function createProvidersConfig(options?: ApplicationConfig, context?: BootstrapContext) {
return {
platformRef: context?.platformRef,
appProviders: [...BROWSER_MODULE_PROVIDERS, ...(options?.providers ?? [])],
platformProviders: INTERNAL_BROWSER_PLATFORM_PROVIDERS,
};
@@ -47,10 +47,12 @@ import {
provideNgReflectAttributes,
ɵSSR_CONTENT_INTEGRITY_MARKER as SSR_CONTENT_INTEGRITY_MARKER,
provideZoneChangeDetection,
signal,
} from '@angular/core';
import {TestBed} from '@angular/core/testing';
import {
bootstrapApplication,
createApplication,
BootstrapContext,
BrowserModule,
provideClientHydration,
@@ -767,6 +769,24 @@ class HiddenModule {}
TestBed.resetTestingModule();
});
it('should render with `createApplication`', async () => {
const output = await renderApplication(
async (context) => {
const appRef = await createApplication(
{
providers: [provideZoneChangeDetection()],
},
context,
);
appRef.bootstrap(createMyAsyncServerApp(true));
return appRef;
},
{document: doc},
);
expect(output).toBe(expectedOutput);
});
it('using long form should work', async () => {
const platform = platformServer([
{