-
Notifications
You must be signed in to change notification settings - Fork 27.1k
Closed
Description
Angular is already generating Injectors on elements for components. We would like to have the same approach for the injector used for bootstrapping and the injector used for dynamic component loading.
With this, we no longer need any metadata about classes / functions in offline compile mode, as all of the metadata (decorators) have been read during offline compile and converted into appropriate code. This means:
- Download size impact:
- We are no longer using
ReflectiveInjectornorReflector/ReflectionCapabilities- this drops about 30kb minified / 6.49k minified gzipped from angular core
- we don't need the
reflect-metadatapolyfill anymore when during offline compile (2.1kb min gzipped) - we don't need to keep the decorators anymore during runtime.
- we don't need to store the constructor arguments any more
- we are generting code for the injectors instead, which needs to be measured how much.
- We are no longer using
- Bootstrap speed
- analyzing the dependencies of classes, normalizing them and creating factories for them during bootstrap of an application can be costly depending on the number of services used. This especially affects bootstrap as the JavaScript vm most probably did not have time to optimize the code.
- this was proven by internal benchmarks for the last bigger change to DI for elements (see #8b000a7f0e9fade5e6a9354532597018c5ad9a55).
- Better global static analyzability of injection of angular apps. In the future, this would allow to check which providers are actually used in an application and report missing providers that services / directives that are used depend upon.
Impact for users:
- This change does not affect runtime compile, only offline compilation.
- This change only affects how users add additional providers to bootstrap / when components are dynamically loaded. Bootrapping / dynamically loading components without additional providers does not change.
- This change does not change how components use providers
Part of #6270
Input and output of the compilation
Declare injectors via a config class like this:
@InjectorConfig({
providers: [SomeService]
})
class MyAppConfig {
constructor(public @Provides(SomeToken) someProp: string) {
}
}
Via runtime or offline compile, we create a InjectorFactory that is usable like this:
var injectorFactory: InjectorFactory<MyAppConfig>;
var parentInjector: Injector;
var injector: Injector = injectorFactory.create(parentInjector, new MyAppConfig('hello'));
expect(injector.get(SomeService)).toBeAndInstanceOf(SomeService);
expect(injector.get(SomeToken)).toBe('hello');
Usage with offline compilation
// Name: drop suffix `Config` if existing and add `InjectorFactory`
import {MyAppInjectorFactory} from 'my_config.ngfactory';
MyAppInjectorFactory.create(...);
Usage with runtime compilation
var componentResolver: ComponentResolver;
// This would also jit the generated code, similar to our component compiler.
componentResolver.resolveInjector(MyAppConfig).then(
(injectorFactory: InjectorFactory<MyAppConfig>) => {
injectorFactory.create(...);
}
);
Consequences
- We can still support the
bootstrap(type, providers)call in@angular/browseras this uses theRuntimeCompileralready, so it can also create a injector config class on the fly with the given providers. -> plunkers stay simpler. - To create the ComponentResolver, we can't use DI any more, as it provides the factory for injectors.
- As the compiler creates the injector factories, the compiler can't be configured via DI, but we rather need factory methods that take the
CompilerConfigand maybe some other parameters.- e.g. platform directives / platform pipes need to become part of the
CompilerConfig,
and not provided via DI (this also unifies their configuration between offline and runtime compile).
- e.g. platform directives / platform pipes need to become part of the
Proposed changes to Angular besides the compiler changes
- [BREAKING] move
ReflectiveInjectorand move it to@angular/commonor into a
separate module as Angular itself does no more use it.- It is still used by e.g. benchpress so we need to keep it.
- Instead, users have to create injector config classes as shown above for both, runtime and offline compile. For runtime compile, we could create these injector config classes on the fly, but to make it easier for users to switch to offline compile they should already use them.
- or maybe just deprecate it?
- move
ReflectorandReflectionCapabilitiesfrom@angular/coreto@angular/compileras the
compiler is the only place where these are used. - make
ComponentResolver(anRuntimeCompiler) part ofPlatformRefand don't use DI to create the providers ofPlatformRef. Still expose an injector inPlatformRefwhich is just based on aMap. - [BREAKING] make platform pipes / platform directives part of
CompilerConfigand define them as arrays ofCompileIdentifierMetadataso they can be used for offline and runtime compile. - [BREAKING] pass
CompilerConfigtobrowserPlatform()as argument instead of getting it via DI.- we might consider using a special
BrowserCompileConfigclass as some parts ofCompilerConfigare implied by using the browser platform (e.g. that platform directives are always defined via their runtime types, i.e. the user only needs to provide an array of types instead ofCompileIdentifierMetadata)
- we might consider using a special
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels