perf: switch angular to use StaticInjector instead of ReflectiveInjector

This change allows ReflectiveInjector to be tree shaken resulting
in not needed Reflect polyfil and smaller bundles.

Code savings for HelloWorld using Closure:

Reflective: bundle.js:  105,864(34,190 gzip)
    Static: bundle.js:  154,889(33,555 gzip)
                            645( 2%)

BREAKING CHANGE:

`platformXXXX()` no longer accepts providers which depend on reflection.
Specifically the method signature when from `Provider[]` to
`StaticProvider[]`.

Example:
Before:
```
[
  MyClass,
  {provide: ClassA, useClass: SubClassA}
]

```

After:
```
[
  {provide: MyClass, deps: [Dep1,...]},
  {provide: ClassA, useClass: SubClassA, deps: [Dep1,...]}
]
```

NOTE: This only applies to platform creation and providers for the JIT
compiler. It does not apply to `@Compotent` or `@NgModule` provides
declarations.

Benchpress note: Previously Benchpress also supported reflective
provides, which now require static providers.

DEPRECATION:

- `ReflectiveInjector` is now deprecated as it will be remove. Use
  `Injector.create` as a replacement.

closes #18496
This commit is contained in:
Miško Hevery
2017-08-03 12:33:29 -07:00
committed by Victor Berchet
parent d9d00bd9b5
commit fcadbf4bf6
94 changed files with 380 additions and 279 deletions

View File

@ -19,7 +19,7 @@ import {isPromise} from '../src/util/lang';
import {ApplicationInitStatus} from './application_init';
import {APP_BOOTSTRAP_LISTENER, PLATFORM_INITIALIZER} from './application_tokens';
import {Console} from './console';
import {Injectable, InjectionToken, Injector, Provider, ReflectiveInjector} from './di';
import {Injectable, InjectionToken, Injector, StaticProvider} from './di';
import {CompilerFactory, CompilerOptions} from './linker/compiler';
import {ComponentFactory, ComponentRef} from './linker/component_factory';
import {ComponentFactoryBoundToModule, ComponentFactoryResolver} from './linker/component_factory_resolver';
@ -99,17 +99,18 @@ export function createPlatform(injector: Injector): PlatformRef {
* @experimental APIs related to application bootstrap are currently under review.
*/
export function createPlatformFactory(
parentPlatformFactory: ((extraProviders?: Provider[]) => PlatformRef) | null, name: string,
providers: Provider[] = []): (extraProviders?: Provider[]) => PlatformRef {
parentPlatformFactory: ((extraProviders?: StaticProvider[]) => PlatformRef) | null,
name: string, providers: StaticProvider[] = []): (extraProviders?: StaticProvider[]) =>
PlatformRef {
const marker = new InjectionToken(`Platform: ${name}`);
return (extraProviders: Provider[] = []) => {
return (extraProviders: StaticProvider[] = []) => {
let platform = getPlatform();
if (!platform || platform.injector.get(ALLOW_MULTIPLE_PLATFORMS, false)) {
if (parentPlatformFactory) {
parentPlatformFactory(
providers.concat(extraProviders).concat({provide: marker, useValue: true}));
} else {
createPlatform(ReflectiveInjector.resolveAndCreate(
createPlatform(Injector.create(
providers.concat(extraProviders).concat({provide: marker, useValue: true})));
}
}
@ -292,8 +293,7 @@ export class PlatformRef_ extends PlatformRef {
// Attention: Don't use ApplicationRef.run here,
// as we want to be sure that all possible constructor calls are inside `ngZone.run`!
return ngZone.run(() => {
const ngZoneInjector =
ReflectiveInjector.resolveAndCreate([{provide: NgZone, useValue: ngZone}], this.injector);
const ngZoneInjector = Injector.create([{provide: NgZone, useValue: ngZone}], this.injector);
const moduleRef = <InternalNgModuleRef<M>>moduleFactory.create(ngZoneInjector);
const exceptionHandler: ErrorHandler = moduleRef.injector.get(ErrorHandler, null);
if (!exceptionHandler) {

View File

@ -6,9 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Optional, Provider, SkipSelf} from '../../di';
import {Optional, SkipSelf, StaticProvider} from '../../di';
import {ChangeDetectorRef} from '../change_detector_ref';
/**
* A type describing supported iterable types.
*
@ -181,7 +182,7 @@ export class IterableDiffers {
* })
* ```
*/
static extend(factories: IterableDifferFactory[]): Provider {
static extend(factories: IterableDifferFactory[]): StaticProvider {
return {
provide: IterableDiffers,
useFactory: (parent: IterableDiffers) => {

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Optional, Provider, SkipSelf} from '../../di';
import {Optional, SkipSelf, StaticProvider} from '../../di';
import {ChangeDetectorRef} from '../change_detector_ref';
@ -156,7 +156,7 @@ export class KeyValueDiffers {
* })
* ```
*/
static extend<S>(factories: KeyValueDifferFactory[]): Provider {
static extend<S>(factories: KeyValueDifferFactory[]): StaticProvider {
return {
provide: KeyValueDiffers,
useFactory: (parent: KeyValueDiffers) => {

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Injectable, InjectionToken} from '../di';
import {Injectable, InjectionToken, StaticProvider} from '../di';
import {MissingTranslationStrategy} from '../i18n/tokens';
import {ViewEncapsulation} from '../metadata';
import {Type} from '../type';
@ -14,6 +14,7 @@ import {Type} from '../type';
import {ComponentFactory} from './component_factory';
import {NgModuleFactory} from './ng_module_factory';
/**
* Combination of NgModuleFactory and ComponentFactorys.
*
@ -101,7 +102,7 @@ export type CompilerOptions = {
useDebug?: boolean,
useJit?: boolean,
defaultEncapsulation?: ViewEncapsulation,
providers?: any[],
providers?: StaticProvider[],
missingTranslation?: MissingTranslationStrategy,
// Whether to support the `<template>` tag and the `template` attribute to define angular
// templates. They have been deprecated in 4.x, `<ng-template>` should be used instead.

View File

@ -9,22 +9,16 @@
import {PlatformRef, PlatformRef_, createPlatformFactory} from './application_ref';
import {PLATFORM_ID} from './application_tokens';
import {Console} from './console';
import {Provider} from './di';
import {Reflector, reflector} from './reflection/reflection';
import {Injector, StaticProvider} from './di';
import {TestabilityRegistry} from './testability/testability';
function _reflector(): Reflector {
return reflector;
}
const _CORE_PLATFORM_PROVIDERS: Provider[] = [
const _CORE_PLATFORM_PROVIDERS: StaticProvider[] = [
// Set a default platform name for platforms that don't set it explicitly.
{provide: PLATFORM_ID, useValue: 'unknown'},
PlatformRef_,
{provide: PlatformRef_, deps: [Injector]},
{provide: PlatformRef, useExisting: PlatformRef_},
{provide: Reflector, useFactory: _reflector, deps: []},
TestabilityRegistry,
Console,
{provide: TestabilityRegistry, deps: []},
{provide: Console, deps: []},
];
/**

View File

@ -190,4 +190,4 @@ export function getQueryValue(
}
return value;
}
}
}

View File

@ -161,7 +161,7 @@ function validateNode(parent: NodeDef | null, node: NodeDef, nodeCount: number)
const parentFlags = parent ? parent.flags : 0;
if ((parentFlags & NodeFlags.TypeElement) === 0) {
throw new Error(
`Illegal State: Provider/Directive nodes need to be children of elements or anchors, at index ${node.index}!`);
`Illegal State: StaticProvider/Directive nodes need to be children of elements or anchors, at index ${node.index}!`);
}
}
if (node.query) {