Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf(core): make more ApplicationModule providers tree-shakable #45102

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion goldens/size-tracking/aio-payloads.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"master": {
"uncompressed": {
"runtime": 4343,
"main": 450729,
"main": 450085,
"polyfills": 37297,
"styles": 70379,
"light-theme": 77582,
Expand Down
10 changes: 5 additions & 5 deletions goldens/size-tracking/integration-payloads.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"master": {
"uncompressed": {
"runtime": 1083,
"main": 127944,
"main": 126218,
"polyfills": 37226
}
}
Expand All @@ -24,7 +24,7 @@
"master": {
"uncompressed": {
"runtime": 1105,
"main": 133608,
"main": 131882,
"polyfills": 37248
}
}
Expand All @@ -33,7 +33,7 @@
"master": {
"uncompressed": {
"runtime": 929,
"main": 126275,
"main": 124544,
"polyfills": 37933
}
}
Expand All @@ -52,7 +52,7 @@
"master": {
"uncompressed": {
"runtime": 1063,
"main": 159637,
"main": 158556,
"polyfills": 36975
}
}
Expand All @@ -61,7 +61,7 @@
"master": {
"uncompressed": {
"runtime": 1070,
"main": 159755,
"main": 158300,
"polyfills": 37242
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/application_init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export const APP_INITIALIZER =
*
* @publicApi
*/
@Injectable()
@Injectable({providedIn: 'root'})
export class ApplicationInitStatus {
private resolve = noop;
private reject = noop;
Expand Down
99 changes: 3 additions & 96 deletions packages/core/src/application_module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,110 +6,17 @@
* found in the LICENSE file at https://angular.io/license
*/

import {APP_INITIALIZER, ApplicationInitStatus} from './application_init';
import {ApplicationRef} from './application_ref';
import {APP_ID_RANDOM_PROVIDER} from './application_tokens';
import {Injector, StaticProvider} from './di';
import {Inject, Optional, SkipSelf} from './di/metadata';
import {ErrorHandler} from './error_handler';
import {DEFAULT_LOCALE_ID, USD_CURRENCY_CODE} from './i18n/localization';
import {DEFAULT_CURRENCY_CODE, LOCALE_ID} from './i18n/tokens';
import {ComponentFactoryResolver} from './linker';
import {Compiler} from './linker/compiler';
import {NgModule} from './metadata';
import {SCHEDULER} from './render3/component_ref';
import {NgZone} from './zone';

declare const $localize: {locale?: string};

export function _localeFactory(locale?: string): string {
return locale || getGlobalLocale();
}
/**
* Work out the locale from the potential global properties.
*
* * Closure Compiler: use `goog.getLocale()`.
* * Ivy enabled: use `$localize.locale`
*/
export function getGlobalLocale(): string {
if (typeof ngI18nClosureMode !== 'undefined' && ngI18nClosureMode &&
typeof goog !== 'undefined' && goog.getLocale() !== 'en') {
// * The default `goog.getLocale()` value is `en`, while Angular used `en-US`.
// * In order to preserve backwards compatibility, we use Angular default value over
// Closure Compiler's one.
return goog.getLocale();
} else {
// KEEP `typeof $localize !== 'undefined' && $localize.locale` IN SYNC WITH THE LOCALIZE
// COMPILE-TIME INLINER.
//
// * During compile time inlining of translations the expression will be replaced
// with a string literal that is the current locale. Other forms of this expression are not
// guaranteed to be replaced.
//
// * During runtime translation evaluation, the developer is required to set `$localize.locale`
// if required, or just to provide their own `LOCALE_ID` provider.
return (typeof $localize !== 'undefined' && $localize.locale) || DEFAULT_LOCALE_ID;
}
}

/**
* A built-in [dependency injection token](guide/glossary#di-token)
* that is used to configure the root injector for bootstrapping.
*/
export const APPLICATION_MODULE_PROVIDERS: StaticProvider[] = [
{
provide: ApplicationRef,
useClass: ApplicationRef,
deps: [NgZone, Injector, ErrorHandler, ComponentFactoryResolver, ApplicationInitStatus]
},
{provide: SCHEDULER, deps: [NgZone], useFactory: zoneSchedulerFactory},
{
provide: ApplicationInitStatus,
useClass: ApplicationInitStatus,
deps: [[new Optional(), APP_INITIALIZER]]
},
{provide: Compiler, useClass: Compiler, deps: []},
APP_ID_RANDOM_PROVIDER,
{
provide: LOCALE_ID,
useFactory: _localeFactory,
deps: [[new Inject(LOCALE_ID), new Optional(), new SkipSelf()]]
},
{provide: DEFAULT_CURRENCY_CODE, useValue: USD_CURRENCY_CODE},
];

/**
* Schedule work at next available slot.
*
* In Ivy this is just `requestAnimationFrame`. For compatibility reasons when bootstrapped
* using `platformRef.bootstrap` we need to use `NgZone.onStable` as the scheduling mechanism.
* This overrides the scheduling mechanism in Ivy to `NgZone.onStable`.
*
* @param ngZone NgZone to use for scheduling.
*/
export function zoneSchedulerFactory(ngZone: NgZone): (fn: () => void) => void {
let queue: (() => void)[] = [];
ngZone.onStable.subscribe(() => {
while (queue.length) {
queue.pop()!();
}
});
return function(fn: () => void) {
queue.push(fn);
};
}

/**
* Configures the root injector for an app with
* providers of `@angular/core` dependencies that `ApplicationRef` needs
* to bootstrap components.
*
* Re-exported by `BrowserModule`, which is included automatically in the root
* `AppModule` when you create a new app with the CLI `new` command.
* `AppModule` when you create a new app with the CLI `new` command. Eagerly injects
* `ApplicationRef` to instantiate it.
*
* @publicApi
*/
@NgModule({providers: APPLICATION_MODULE_PROVIDERS})
@NgModule()
export class ApplicationModule {
// Inject ApplicationRef to make it eager...
constructor(appRef: ApplicationRef) {}
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/application_ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@ function optionsReducer<T extends Object>(dst: any, objs: T|T[]): T {
*
* @publicApi
*/
@Injectable()
@Injectable({providedIn: 'root'})
export class ApplicationRef {
/** @internal */
private _bootstrapListeners: ((compRef: ComponentRef<any>) => void)[] = [];
Expand Down
5 changes: 4 additions & 1 deletion packages/core/src/application_tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ import {ComponentRef} from './linker/component_factory';
*
* @publicApi
*/
export const APP_ID = new InjectionToken<string>('AppId');
export const APP_ID = new InjectionToken<string>('AppId', {
providedIn: 'root',
factory: _appIdRandomProviderFactory,
});

export function _appIdRandomProviderFactory() {
return `${_randomChar()}${_randomChar()}${_randomChar()}`;
Expand Down
44 changes: 42 additions & 2 deletions packages/core/src/i18n/tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,39 @@
*/

import {InjectionToken} from '../di/injection_token';
import {inject} from '../di/injector_compatibility';
import {InjectFlags} from '../di/interface/injector';

import {DEFAULT_LOCALE_ID, USD_CURRENCY_CODE} from './localization';

declare const $localize: {locale?: string};

/**
* Work out the locale from the potential global properties.
*
* * Closure Compiler: use `goog.getLocale()`.
* * Ivy enabled: use `$localize.locale`
*/
export function getGlobalLocale(): string {
if (typeof ngI18nClosureMode !== 'undefined' && ngI18nClosureMode &&
typeof goog !== 'undefined' && goog.getLocale() !== 'en') {
// * The default `goog.getLocale()` value is `en`, while Angular used `en-US`.
// * In order to preserve backwards compatibility, we use Angular default value over
// Closure Compiler's one.
return goog.getLocale();
} else {
// KEEP `typeof $localize !== 'undefined' && $localize.locale` IN SYNC WITH THE LOCALIZE
// COMPILE-TIME INLINER.
//
// * During compile time inlining of translations the expression will be replaced
// with a string literal that is the current locale. Other forms of this expression are not
// guaranteed to be replaced.
//
// * During runtime translation evaluation, the developer is required to set `$localize.locale`
// if required, or just to provide their own `LOCALE_ID` provider.
return (typeof $localize !== 'undefined' && $localize.locale) || DEFAULT_LOCALE_ID;
}
}

/**
* Provide this token to set the locale of your application.
Expand All @@ -30,7 +63,11 @@ import {InjectionToken} from '../di/injection_token';
*
* @publicApi
*/
export const LOCALE_ID = new InjectionToken<string>('LocaleId');
export const LOCALE_ID: InjectionToken<string> = new InjectionToken('LocaleId', {
providedIn: 'root',
factory: () =>
inject(LOCALE_ID, InjectFlags.Optional | InjectFlags.SkipSelf) || getGlobalLocale(),
});

/**
* Provide this token to set the default currency code your application uses for
Expand Down Expand Up @@ -70,7 +107,10 @@ export const LOCALE_ID = new InjectionToken<string>('LocaleId');
*
* @publicApi
*/
export const DEFAULT_CURRENCY_CODE = new InjectionToken<string>('DefaultCurrencyCode');
export const DEFAULT_CURRENCY_CODE = new InjectionToken<string>('DefaultCurrencyCode', {
providedIn: 'root',
factory: () => USD_CURRENCY_CODE,
});

/**
* Use this token at bootstrap to provide the content of your translation file (`xtb`,
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/linker/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class ModuleWithComponentFactories<T> {
* See [JIT API changes due to ViewEngine deprecation](guide/deprecations#jit-api-changes) for
* additional context.
*/
@Injectable()
@Injectable({providedIn: 'root'})
export class Compiler {
/**
* Compiles the given NgModule and all of its components. All templates of the components listed
Expand Down
11 changes: 0 additions & 11 deletions packages/core/src/render3/component_ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
*/

import {ChangeDetectorRef as ViewEngine_ChangeDetectorRef} from '../change_detection/change_detector_ref';
import {InjectionToken} from '../di/injection_token';
import {Injector} from '../di/injector';
import {InjectFlags} from '../di/interface/injector';
import {ProviderToken} from '../di/provider_token';
Expand Down Expand Up @@ -36,7 +35,6 @@ import {createElementNode, writeDirectClass} from './node_manipulation';
import {extractAttrsAndClassesFromSelector, stringifyCSSSelectorList} from './node_selector_matcher';
import {enterView, leaveView} from './state';
import {setUpAttributes} from './util/attrs_utils';
import {defaultScheduler} from './util/misc_utils';
import {getTNode} from './util/view_utils';
import {RootViewRef, ViewRef} from './view_ref';

Expand Down Expand Up @@ -71,15 +69,6 @@ function getNamespace(elementName: string): string|null {
return name === 'svg' ? SVG_NAMESPACE : (name === 'math' ? MATH_ML_NAMESPACE : null);
}

/**
* A change detection scheduler token for {@link RootContext}. This token is the default value used
* for the default `RootContext` found in the {@link ROOT_CONTEXT} token.
*/
export const SCHEDULER = new InjectionToken<((fn: () => void) => void)>('SCHEDULER_TOKEN', {
providedIn: 'root',
factory: () => defaultScheduler,
});

function createChainedInjector(rootViewInjector: Injector, moduleInjector: Injector): Injector {
return {
get: <T>(token: ProviderToken<T>, notFoundValue?: T, flags?: InjectFlags): T => {
Expand Down