feat(core): Create StaticInjector which does not depend on Reflect polyfill#18496
feat(core): Create StaticInjector which does not depend on Reflect polyfill#18496mhevery wants to merge 2 commits into
Conversation
fa8f677 to
750f4b7
Compare
There was a problem hiding this comment.
Is duplicate signature intended?
There was a problem hiding this comment.
97fc905 to
5e07e15
Compare
5e07e15 to
4158b94
Compare
85e97a0 to
763a3a9
Compare
| * | ||
| * @stable | ||
| */ | ||
| export type Provider = |
There was a problem hiding this comment.
Provider is also used in our decorators (e.g. @NgModule). It seems wrong that it is now defined in a file called reflective_injector_interfaces. I think it should be defined in e.g. di/metadata.ts and then this file can reexport it if we really need this file.
There was a problem hiding this comment.
moved back to provider.ts
| let value: any = EMPTY; | ||
| let useNew: boolean = false; | ||
| let provide = resolveForwardRef(provider.provide); | ||
| if (USE_VALUE in provider) { |
There was a problem hiding this comment.
Why use in here? For all the cases we can just check for e.g. .useFactory !== undefined, and the fall through case is useValue...
There was a problem hiding this comment.
This would both be faster and remove getClosureSafeProperty
There was a problem hiding this comment.
I can't use .useValue since the value could be undefined. So since I started using in with useValue, I am just being consistent.
There was a problem hiding this comment.
changed, only USE_VALUE is special
| } | ||
|
|
||
| interface Records { | ||
| [key: string]: Record; |
There was a problem hiding this comment.
Why use an object hash and not a Map directly?
There was a problem hiding this comment.
See: https://stackoverflow.com/questions/10258071/class-object-vs-hashmap
Summary: faster, smaller, no polyfill
|
|
||
| let idCounter = 0; | ||
|
|
||
| function getId(obj: any): string { |
There was a problem hiding this comment.
I think using a Map is simpler, and shouldn't be slower AFAIK.
| } | ||
| } | ||
| if (useNew) { | ||
| obj = Object.create(fn.prototype); |
There was a problem hiding this comment.
This won't work if users run in real ES6 mode.
Consider doing a obj = new fn(...deps).
| const NG_TOKEN_PATH = 'ngTokenPath'; | ||
| const NG_TEMP_TOKEN_PATH = 'ngTempTokenPath'; | ||
| const ID_EXPANDO = '__symbol_angular_id_' + new Date().getTime() + '__'; | ||
| const OPT_OPTIONAL = 1; |
There was a problem hiding this comment.
Consider using an enum for the bitmask here and add the suffix Flags (which is what we do everywhere else):
enum OptionFlags {
Optional = 1 << 0,
CheckSelf = 1 << 1,
CheckParent = 1 << 2,
}
| if (!(e instanceof Error)) { | ||
| e = new Error(e); | ||
| } | ||
| const path: any[] = e[NG_TEMP_TOKEN_PATH] = e[NG_TEMP_TOKEN_PATH] || []; |
There was a problem hiding this comment.
Consider passing the tokenPathOnError directly to tryResolveToken, so you don't need to patch it unto the error (as it is a private field anyways).
There was a problem hiding this comment.
I don't want to have the cost of tokenPath only in the case of an error. Hence it is patched on Error
There was a problem hiding this comment.
I mean you can just create it as an empty array, and only fill it in case of an error in the various catch clauses. This way, the cost is only to create the empty array, but not to fill it.
| if (depRecords.length) { | ||
| deps = []; | ||
| for (let i = 0; i < depRecords.length; i++) { | ||
| const depRecord: DependencyRecord = depRecords[i], options = depRecord.options, |
There was a problem hiding this comment.
Maybe have separate const statements to clear up the formatting?
| } catch (e) { | ||
| const tokenPath: any[] = e[NG_TEMP_TOKEN_PATH]; | ||
| let message: string = e.message; | ||
| message = message && message.charAt(0) === NO_NEW_LINE ? message.substr(1) : '\n' + message; |
There was a problem hiding this comment.
Consider adding the logic of adding a newLine or not to staticError
| let message: string = e.message; | ||
| message = message && message.charAt(0) === NO_NEW_LINE ? message.substr(1) : '\n' + message; | ||
| const error = staticError(message, tokenPath); | ||
| e.message = error.message; |
There was a problem hiding this comment.
Did you check if this prints nicely in the browser console? AFAIK it does not.
Another solution would be to throw 2 errors: 1 for flow control where it is now, and another one here with the proper message passed to new Error(...)
There was a problem hiding this comment.
Yes, it looks good in console.
|
|
||
| describe('StaticClassProvider', () => { | ||
| it('works', () => { | ||
| // #docregion StaticClassProvider |
There was a problem hiding this comment.
I think this is missing a guide that refers to these new #docregions...
There was a problem hiding this comment.
Not sure I understand. It is present.
There was a problem hiding this comment.
Ah, never mind, I remembered incorrectly how the guides work.
tbosch
left a comment
There was a problem hiding this comment.
Looks good in general, needs cleanup.
5c8714d to
fd8649c
Compare
fd8649c to
00f50cb
Compare
86d6f8d to
6fc47e6
Compare
|
blocked on tap/164481065 |
|
@vicb here is the fix http://cl/164500104 |
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.
6fc47e6 to
5db475c
Compare
follow-up for angular#18496
|
Would #13820 be affected by this? Seems StaticInjector does not require |
|
Commit message fcadbf4 reads like you are indeed right. They deprecated or even got rid of the reflective resolver altogether. |
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 angular#18496
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 angular#18496
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 angular#18496
|
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |

No description provided.