feat(ivy): generate ngInjectorDef for @NgModule in JIT mode (#24632)
This commit takes advantage of the @angular/compiler work for ngInjectorDef in AOT mode in order to generate the same definition in JIT mode. PR Close #24632
This commit is contained in:
parent
ae9418c7de
commit
89c442270a
@ -70,6 +70,7 @@ module.exports = function(config) {
|
|||||||
'dist/all/@angular/compiler/test/aot/**',
|
'dist/all/@angular/compiler/test/aot/**',
|
||||||
'dist/all/@angular/compiler/test/render3/**',
|
'dist/all/@angular/compiler/test/render3/**',
|
||||||
'dist/all/@angular/core/test/bundling/**',
|
'dist/all/@angular/core/test/bundling/**',
|
||||||
|
'dist/all/@angular/core/test/render3/**',
|
||||||
'dist/all/@angular/elements/schematics/**',
|
'dist/all/@angular/elements/schematics/**',
|
||||||
'dist/all/@angular/examples/**/e2e_test/*',
|
'dist/all/@angular/examples/**/e2e_test/*',
|
||||||
'dist/all/@angular/language-service/**',
|
'dist/all/@angular/language-service/**',
|
||||||
|
@ -12,5 +12,6 @@ const TARGET = {} as any;
|
|||||||
|
|
||||||
export const NG_COMPONENT_DEF = getClosureSafeProperty({ngComponentDef: TARGET}, TARGET);
|
export const NG_COMPONENT_DEF = getClosureSafeProperty({ngComponentDef: TARGET}, TARGET);
|
||||||
export const NG_DIRECTIVE_DEF = getClosureSafeProperty({ngDirectiveDef: TARGET}, TARGET);
|
export const NG_DIRECTIVE_DEF = getClosureSafeProperty({ngDirectiveDef: TARGET}, TARGET);
|
||||||
|
export const NG_INJECTOR_DEF = getClosureSafeProperty({ngInjectorDef: TARGET}, TARGET);
|
||||||
export const NG_PIPE_DEF = getClosureSafeProperty({ngPipeDef: TARGET}, TARGET);
|
export const NG_PIPE_DEF = getClosureSafeProperty({ngPipeDef: TARGET}, TARGET);
|
||||||
export const NG_MODULE_DEF = getClosureSafeProperty({ngModuleDef: TARGET}, TARGET);
|
export const NG_MODULE_DEF = getClosureSafeProperty({ngModuleDef: TARGET}, TARGET);
|
||||||
|
@ -6,24 +6,25 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Expression, R3NgModuleMetadata, WrappedNodeExpr, compileNgModule as compileR3NgModule, jitExpression} from '@angular/compiler';
|
import {Expression, R3InjectorMetadata, R3NgModuleMetadata, WrappedNodeExpr, compileInjector, compileNgModule as compileR3NgModule, jitExpression} from '@angular/compiler';
|
||||||
|
|
||||||
import {ModuleWithProviders, NgModule, NgModuleDefInternal, NgModuleTransitiveScopes} from '../../metadata/ng_module';
|
import {ModuleWithProviders, NgModule, NgModuleDefInternal, NgModuleTransitiveScopes} from '../../metadata/ng_module';
|
||||||
import {Type} from '../../type';
|
import {Type} from '../../type';
|
||||||
import {ComponentDefInternal} from '../interfaces/definition';
|
import {ComponentDefInternal} from '../interfaces/definition';
|
||||||
|
|
||||||
import {angularCoreEnv} from './environment';
|
import {angularCoreEnv} from './environment';
|
||||||
import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF, NG_MODULE_DEF, NG_PIPE_DEF} from './fields';
|
import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF, NG_INJECTOR_DEF, NG_MODULE_DEF, NG_PIPE_DEF} from './fields';
|
||||||
|
import {reflectDependencies} from './util';
|
||||||
|
|
||||||
const EMPTY_ARRAY: Type<any>[] = [];
|
const EMPTY_ARRAY: Type<any>[] = [];
|
||||||
|
|
||||||
export function compileNgModule(type: Type<any>, ngModule: NgModule): void {
|
export function compileNgModule(type: Type<any>, ngModule: NgModule): void {
|
||||||
const declarations: Type<any>[] = flatten(ngModule.declarations || EMPTY_ARRAY);
|
const declarations: Type<any>[] = flatten(ngModule.declarations || EMPTY_ARRAY);
|
||||||
|
|
||||||
let def: any = null;
|
let ngModuleDef: any = null;
|
||||||
Object.defineProperty(type, NG_MODULE_DEF, {
|
Object.defineProperty(type, NG_MODULE_DEF, {
|
||||||
get: () => {
|
get: () => {
|
||||||
if (def === null) {
|
if (ngModuleDef === null) {
|
||||||
const meta: R3NgModuleMetadata = {
|
const meta: R3NgModuleMetadata = {
|
||||||
type: wrap(type),
|
type: wrap(type),
|
||||||
bootstrap: flatten(ngModule.bootstrap || EMPTY_ARRAY).map(wrap),
|
bootstrap: flatten(ngModule.bootstrap || EMPTY_ARRAY).map(wrap),
|
||||||
@ -35,9 +36,32 @@ export function compileNgModule(type: Type<any>, ngModule: NgModule): void {
|
|||||||
emitInline: true,
|
emitInline: true,
|
||||||
};
|
};
|
||||||
const res = compileR3NgModule(meta);
|
const res = compileR3NgModule(meta);
|
||||||
def = jitExpression(res.expression, angularCoreEnv, `ng://${type.name}/ngModuleDef.js`);
|
ngModuleDef =
|
||||||
|
jitExpression(res.expression, angularCoreEnv, `ng://${type.name}/ngModuleDef.js`);
|
||||||
}
|
}
|
||||||
return def;
|
return ngModuleDef;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
let ngInjectorDef: any = null;
|
||||||
|
Object.defineProperty(type, NG_INJECTOR_DEF, {
|
||||||
|
get: () => {
|
||||||
|
if (ngInjectorDef === null) {
|
||||||
|
const meta: R3InjectorMetadata = {
|
||||||
|
name: type.name,
|
||||||
|
type: wrap(type),
|
||||||
|
deps: reflectDependencies(type),
|
||||||
|
providers: new WrappedNodeExpr(ngModule.providers || EMPTY_ARRAY),
|
||||||
|
imports: new WrappedNodeExpr([
|
||||||
|
ngModule.imports || EMPTY_ARRAY,
|
||||||
|
ngModule.exports || EMPTY_ARRAY,
|
||||||
|
]),
|
||||||
|
};
|
||||||
|
const res = compileInjector(meta);
|
||||||
|
ngInjectorDef =
|
||||||
|
jitExpression(res.expression, angularCoreEnv, `ng://${type.name}/ngInjectorDef.js`);
|
||||||
|
}
|
||||||
|
return ngInjectorDef;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -35,10 +35,3 @@ jasmine_node_test(
|
|||||||
":ivy_node_lib",
|
":ivy_node_lib",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
ts_web_test_suite(
|
|
||||||
name = "ivy_web",
|
|
||||||
deps = [
|
|
||||||
":ivy_lib",
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
@ -6,6 +6,9 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import 'reflect-metadata';
|
||||||
|
|
||||||
|
import {InjectorDef, defineInjectable} from '@angular/core/src/di/defs';
|
||||||
import {Injectable} from '@angular/core/src/di/injectable';
|
import {Injectable} from '@angular/core/src/di/injectable';
|
||||||
import {inject, setCurrentInjector} from '@angular/core/src/di/injector';
|
import {inject, setCurrentInjector} from '@angular/core/src/di/injector';
|
||||||
import {ivyEnabled} from '@angular/core/src/ivy_switch';
|
import {ivyEnabled} from '@angular/core/src/ivy_switch';
|
||||||
@ -140,6 +143,31 @@ ivyEnabled && describe('render3 jit', () => {
|
|||||||
expect(moduleDef.declarations[0]).toBe(Cmp);
|
expect(moduleDef.declarations[0]).toBe(Cmp);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('compiles a module to an ngInjectorDef with the providers', () => {
|
||||||
|
class Token {
|
||||||
|
static ngInjectableDef = defineInjectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
factory: () => 'default',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
providers: [{provide: Token, useValue: 'test'}],
|
||||||
|
})
|
||||||
|
class Module {
|
||||||
|
constructor(public token: Token) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
const injectorDef: InjectorDef<Module> = (Module as any).ngInjectorDef;
|
||||||
|
const instance = injectorDef.factory();
|
||||||
|
|
||||||
|
// Since the instance was created outside of an injector using the module, the
|
||||||
|
// injection will use the default provider, not the provider from the module.
|
||||||
|
expect(instance.token).toBe('default');
|
||||||
|
|
||||||
|
expect(injectorDef.providers).toEqual([{provide: Token, useValue: 'test'}]);
|
||||||
|
});
|
||||||
|
|
||||||
it('patches a module onto the component', () => {
|
it('patches a module onto the component', () => {
|
||||||
@Component({
|
@Component({
|
||||||
template: 'foo',
|
template: 'foo',
|
||||||
|
@ -14,6 +14,7 @@ import {angularCoreEnv} from '../../src/render3/jit/environment';
|
|||||||
const INTERFACE_EXCEPTIONS = new Set<string>([
|
const INTERFACE_EXCEPTIONS = new Set<string>([
|
||||||
'ComponentDef',
|
'ComponentDef',
|
||||||
'DirectiveDef',
|
'DirectiveDef',
|
||||||
|
'InjectorDef',
|
||||||
'NgModuleDef',
|
'NgModuleDef',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user