mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
feat(core): introduce createApplication API (#46475)
The `createApplication` function makes it possible to create an application instance (represented by the `ApplicationRef`) without bootstrapping any components. It is useful in the situations where ones wants to decouple and delay components rendering and / or render multiple root components in one application. Angular elements can use this API to create custom element types with an environment linked to a created application. PR Close #46475
This commit is contained in:
committed by
Jessica Janiuk
parent
6fed377140
commit
4b377d3a6d
@@ -177,7 +177,8 @@ export function runPlatformInitializers(injector: Injector): void {
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal bootstrap application API that implements the core bootstrap logic.
|
||||
* Internal create application API that implements the core application creation logic and optional
|
||||
* bootstrap logic.
|
||||
*
|
||||
* Platforms (such as `platform-browser`) may require different set of application and platform
|
||||
* providers for an application to function correctly. As a result, platforms may use this function
|
||||
@@ -186,17 +187,20 @@ export function runPlatformInitializers(injector: Injector): void {
|
||||
*
|
||||
* @returns A promise that returns an `ApplicationRef` instance once resolved.
|
||||
*/
|
||||
export function internalBootstrapApplication(config: {
|
||||
rootComponent: Type<unknown>,
|
||||
export function internalCreateApplication(config: {
|
||||
rootComponent?: Type<unknown>,
|
||||
appProviders?: Array<Provider|ImportedNgModuleProviders>,
|
||||
platformProviders?: Provider[],
|
||||
}): Promise<ApplicationRef> {
|
||||
const {rootComponent, appProviders, platformProviders} = config;
|
||||
NG_DEV_MODE && assertStandaloneComponentType(rootComponent);
|
||||
|
||||
if (NG_DEV_MODE && rootComponent !== undefined) {
|
||||
assertStandaloneComponentType(rootComponent);
|
||||
}
|
||||
|
||||
const platformInjector = createOrReusePlatformInjector(platformProviders as StaticProvider[]);
|
||||
|
||||
const ngZone = new NgZone(getNgZoneOptions());
|
||||
const ngZone = getNgZone('zone.js', getNgZoneOptions());
|
||||
|
||||
return ngZone.run(() => {
|
||||
// Create root application injector based on a set of providers configured at the platform
|
||||
@@ -205,10 +209,11 @@ export function internalBootstrapApplication(config: {
|
||||
{provide: NgZone, useValue: ngZone}, //
|
||||
...(appProviders || []), //
|
||||
];
|
||||
const appInjector = createEnvironmentInjector(
|
||||
|
||||
const envInjector = createEnvironmentInjector(
|
||||
allAppProviders, platformInjector as EnvironmentInjector, 'Environment Injector');
|
||||
|
||||
const exceptionHandler: ErrorHandler|null = appInjector.get(ErrorHandler, null);
|
||||
const exceptionHandler: ErrorHandler|null = envInjector.get(ErrorHandler, null);
|
||||
if (NG_DEV_MODE && !exceptionHandler) {
|
||||
throw new RuntimeError(
|
||||
RuntimeErrorCode.ERROR_HANDLER_NOT_FOUND,
|
||||
@@ -223,27 +228,30 @@ export function internalBootstrapApplication(config: {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// If the whole platform is destroyed, invoke the `destroy` method
|
||||
// for all bootstrapped applications as well.
|
||||
const destroyListener = () => envInjector.destroy();
|
||||
const onPlatformDestroyListeners = platformInjector.get(PLATFORM_DESTROY_LISTENERS);
|
||||
onPlatformDestroyListeners.add(destroyListener);
|
||||
|
||||
envInjector.onDestroy(() => {
|
||||
onErrorSubscription.unsubscribe();
|
||||
onPlatformDestroyListeners.delete(destroyListener);
|
||||
});
|
||||
|
||||
return _callAndReportToErrorHandler(exceptionHandler!, ngZone, () => {
|
||||
const initStatus = appInjector.get(ApplicationInitStatus);
|
||||
const initStatus = envInjector.get(ApplicationInitStatus);
|
||||
initStatus.runInitializers();
|
||||
|
||||
return initStatus.donePromise.then(() => {
|
||||
const localeId = appInjector.get(LOCALE_ID, DEFAULT_LOCALE_ID);
|
||||
const localeId = envInjector.get(LOCALE_ID, DEFAULT_LOCALE_ID);
|
||||
setLocaleId(localeId || DEFAULT_LOCALE_ID);
|
||||
|
||||
const appRef = appInjector.get(ApplicationRef);
|
||||
|
||||
// If the whole platform is destroyed, invoke the `destroy` method
|
||||
// for all bootstrapped applications as well.
|
||||
const destroyListener = () => appRef.destroy();
|
||||
const onPlatformDestroyListeners = platformInjector.get(PLATFORM_DESTROY_LISTENERS, null);
|
||||
onPlatformDestroyListeners?.add(destroyListener);
|
||||
|
||||
appRef.onDestroy(() => {
|
||||
onPlatformDestroyListeners?.delete(destroyListener);
|
||||
onErrorSubscription.unsubscribe();
|
||||
});
|
||||
|
||||
appRef.bootstrap(rootComponent);
|
||||
const appRef = envInjector.get(ApplicationRef);
|
||||
if (rootComponent !== undefined) {
|
||||
appRef.bootstrap(rootComponent);
|
||||
}
|
||||
return appRef;
|
||||
});
|
||||
});
|
||||
@@ -493,7 +501,7 @@ export class PlatformRef {
|
||||
}
|
||||
|
||||
private _moduleDoBootstrap(moduleRef: InternalNgModuleRef<any>): void {
|
||||
const appRef = moduleRef.injector.get(ApplicationRef) as ApplicationRef;
|
||||
const appRef = moduleRef.injector.get(ApplicationRef);
|
||||
if (moduleRef._bootstrapComponents.length > 0) {
|
||||
moduleRef._bootstrapComponents.forEach(f => appRef.bootstrap(f));
|
||||
} else if (moduleRef.instance.ngDoBootstrap) {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
export {ALLOW_MULTIPLE_PLATFORMS as ɵALLOW_MULTIPLE_PLATFORMS, internalBootstrapApplication as ɵinternalBootstrapApplication} from './application_ref';
|
||||
export {ALLOW_MULTIPLE_PLATFORMS as ɵALLOW_MULTIPLE_PLATFORMS, internalCreateApplication as ɵinternalCreateApplication} from './application_ref';
|
||||
export {APP_ID_RANDOM_PROVIDER as ɵAPP_ID_RANDOM_PROVIDER} from './application_tokens';
|
||||
export {defaultIterableDiffers as ɵdefaultIterableDiffers, defaultKeyValueDiffers as ɵdefaultKeyValueDiffers} from './change_detection/change_detection';
|
||||
export {ChangeDetectorStatus as ɵChangeDetectorStatus, isDefaultChangeDetectionStrategy as ɵisDefaultChangeDetectionStrategy} from './change_detection/constants';
|
||||
|
||||
@@ -333,20 +333,26 @@ class SomeComponent {
|
||||
withModule(
|
||||
{providers},
|
||||
waitForAsync(inject([EnvironmentInjector], (parentInjector: EnvironmentInjector) => {
|
||||
// This is a temporary type to represent an instance of an R3Injector, which
|
||||
// can be destroyed.
|
||||
// The type will be replaced with a different one once destroyable injector
|
||||
// type is available.
|
||||
type DestroyableInjector = EnvironmentInjector&{destroyed?: boolean};
|
||||
|
||||
createRootEl();
|
||||
|
||||
const injector = createApplicationRefInjector(parentInjector);
|
||||
const injector = createApplicationRefInjector(parentInjector) as DestroyableInjector;
|
||||
|
||||
const appRef = injector.get(ApplicationRef);
|
||||
appRef.bootstrap(SomeComponent);
|
||||
|
||||
expect(appRef.destroyed).toBeFalse();
|
||||
expect((injector as any).destroyed).toBeFalse();
|
||||
expect(injector.destroyed).toBeFalse();
|
||||
|
||||
appRef.destroy();
|
||||
|
||||
expect(appRef.destroyed).toBeTrue();
|
||||
expect((injector as any).destroyed).toBeTrue();
|
||||
expect(injector.destroyed).toBeTrue();
|
||||
}))));
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user