feat(ivy): register NgModules with ids when compiled with AOT (#29980)
This commit adds registration of AOT compiled NgModules that have 'id' properties set in their metadata. Such modules have a call to registerNgModuleType() emitted as part of compilation. The JIT behavior of this code is already in place. This is required for module loading systems (such as g3) which rely on getModuleFactory(). PR Close #29980
This commit is contained in:
parent
4229b41057
commit
0df719a461
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Expression, ExternalExpr, InvokeFunctionExpr, LiteralArrayExpr, R3Identifiers, R3InjectorMetadata, R3NgModuleMetadata, R3Reference, Statement, WrappedNodeExpr, compileInjector, compileNgModule} from '@angular/compiler';
|
import {Expression, ExternalExpr, InvokeFunctionExpr, LiteralArrayExpr, LiteralExpr, R3Identifiers, R3InjectorMetadata, R3NgModuleMetadata, R3Reference, Statement, WrappedNodeExpr, compileInjector, compileNgModule} from '@angular/compiler';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
|
||||||
|
@ -28,6 +28,7 @@ export interface NgModuleAnalysis {
|
||||||
metadataStmt: Statement|null;
|
metadataStmt: Statement|null;
|
||||||
declarations: Reference<ClassDeclaration>[];
|
declarations: Reference<ClassDeclaration>[];
|
||||||
exports: Reference<ClassDeclaration>[];
|
exports: Reference<ClassDeclaration>[];
|
||||||
|
id: string|null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -119,6 +120,17 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
|
||||||
bootstrapRefs = this.resolveTypeList(expr, bootstrapMeta, name, 'bootstrap');
|
bootstrapRefs = this.resolveTypeList(expr, bootstrapMeta, name, 'bootstrap');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let id: string|null = null;
|
||||||
|
if (ngModule.has('id')) {
|
||||||
|
const expr = ngModule.get('id') !;
|
||||||
|
const value = this.evaluator.evaluate(expr);
|
||||||
|
if (typeof value !== 'string') {
|
||||||
|
throw new FatalDiagnosticError(
|
||||||
|
ErrorCode.VALUE_HAS_WRONG_TYPE, expr, `NgModule.id must be a string`);
|
||||||
|
}
|
||||||
|
id = value;
|
||||||
|
}
|
||||||
|
|
||||||
// Register this module's information with the LocalModuleScopeRegistry. This ensures that
|
// Register this module's information with the LocalModuleScopeRegistry. This ensures that
|
||||||
// during the compile() phase, the module's metadata is available for selector scope
|
// during the compile() phase, the module's metadata is available for selector scope
|
||||||
// computation.
|
// computation.
|
||||||
|
@ -184,6 +196,7 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
|
||||||
|
|
||||||
return {
|
return {
|
||||||
analysis: {
|
analysis: {
|
||||||
|
id,
|
||||||
ngModuleDef,
|
ngModuleDef,
|
||||||
ngInjectorDef,
|
ngInjectorDef,
|
||||||
declarations: declarationRefs,
|
declarations: declarationRefs,
|
||||||
|
@ -247,6 +260,12 @@ export class NgModuleDecoratorHandler implements DecoratorHandler<NgModuleAnalys
|
||||||
ngModuleStatements.push(callExpr.toStmt());
|
ngModuleStatements.push(callExpr.toStmt());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (analysis.id !== null) {
|
||||||
|
const registerNgModuleType = new ExternalExpr(R3Identifiers.registerNgModuleType);
|
||||||
|
const callExpr = registerNgModuleType.callFn(
|
||||||
|
[new LiteralExpr(analysis.id), new WrappedNodeExpr(node.name)]);
|
||||||
|
ngModuleStatements.push(callExpr.toStmt());
|
||||||
|
}
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
name: 'ngModuleDef',
|
name: 'ngModuleDef',
|
||||||
|
|
|
@ -484,6 +484,21 @@ describe('ngtsc behavioral tests', () => {
|
||||||
expect(jsContents).not.toContain('\u0275\u0275setNgModuleScope(TestModule,');
|
expect(jsContents).not.toContain('\u0275\u0275setNgModuleScope(TestModule,');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should emit a \u0275registerNgModuleType call when the module has an id', () => {
|
||||||
|
env.tsconfig();
|
||||||
|
env.write('test.ts', `
|
||||||
|
import {NgModule} from '@angular/core';
|
||||||
|
|
||||||
|
@NgModule({id: 'test'})
|
||||||
|
export class TestModule {}
|
||||||
|
`);
|
||||||
|
|
||||||
|
env.driveMain();
|
||||||
|
|
||||||
|
const jsContents = env.getContents('test.js');
|
||||||
|
expect(jsContents).toContain('i0.\u0275registerNgModuleType("test", TestModule);');
|
||||||
|
});
|
||||||
|
|
||||||
it('should filter out directives and pipes from module exports in the injector def', () => {
|
it('should filter out directives and pipes from module exports in the injector def', () => {
|
||||||
env.tsconfig();
|
env.tsconfig();
|
||||||
env.write('test.ts', `
|
env.write('test.ts', `
|
||||||
|
|
|
@ -229,6 +229,9 @@ export class Identifiers {
|
||||||
moduleName: CORE,
|
moduleName: CORE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static registerNgModuleType:
|
||||||
|
o.ExternalReference = {name: 'ɵregisterNgModuleType', moduleName: CORE};
|
||||||
|
|
||||||
// sanitization-related functions
|
// sanitization-related functions
|
||||||
static sanitizeHtml: o.ExternalReference = {name: 'ɵɵsanitizeHtml', moduleName: CORE};
|
static sanitizeHtml: o.ExternalReference = {name: 'ɵɵsanitizeHtml', moduleName: CORE};
|
||||||
static sanitizeStyle: o.ExternalReference = {name: 'ɵɵsanitizeStyle', moduleName: CORE};
|
static sanitizeStyle: o.ExternalReference = {name: 'ɵɵsanitizeStyle', moduleName: CORE};
|
||||||
|
|
|
@ -268,7 +268,10 @@ export {
|
||||||
SWITCH_RENDERER2_FACTORY__POST_R3__ as ɵSWITCH_RENDERER2_FACTORY__POST_R3__,
|
SWITCH_RENDERER2_FACTORY__POST_R3__ as ɵSWITCH_RENDERER2_FACTORY__POST_R3__,
|
||||||
} from './render/api';
|
} from './render/api';
|
||||||
|
|
||||||
export {getModuleFactory__POST_R3__ as ɵgetModuleFactory__POST_R3__} from './linker/ng_module_factory_loader';
|
export {
|
||||||
|
getModuleFactory__POST_R3__ as ɵgetModuleFactory__POST_R3__,
|
||||||
|
registerNgModuleType as ɵregisterNgModuleType,
|
||||||
|
} from './linker/ng_module_factory_loader';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
publishGlobalUtil as ɵpublishGlobalUtil,
|
publishGlobalUtil as ɵpublishGlobalUtil,
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
import {ɵɵdefineInjectable, ɵɵdefineInjector,} from '../../di/interface/defs';
|
import {ɵɵdefineInjectable, ɵɵdefineInjector,} from '../../di/interface/defs';
|
||||||
import {ɵɵinject} from '../../di/injector_compatibility';
|
import {ɵɵinject} from '../../di/injector_compatibility';
|
||||||
import * as r3 from '../index';
|
import * as r3 from '../index';
|
||||||
|
import {registerNgModuleType} from '../../linker/ng_module_factory_loader';
|
||||||
import * as sanitization from '../../sanitization/sanitization';
|
import * as sanitization from '../../sanitization/sanitization';
|
||||||
|
|
||||||
|
|
||||||
|
@ -130,5 +131,7 @@ export const angularCoreEnv: {[name: string]: Function} = {
|
||||||
'ɵɵsanitizeResourceUrl': sanitization.ɵɵsanitizeResourceUrl,
|
'ɵɵsanitizeResourceUrl': sanitization.ɵɵsanitizeResourceUrl,
|
||||||
'ɵɵsanitizeScript': sanitization.ɵɵsanitizeScript,
|
'ɵɵsanitizeScript': sanitization.ɵɵsanitizeScript,
|
||||||
'ɵɵsanitizeUrl': sanitization.ɵɵsanitizeUrl,
|
'ɵɵsanitizeUrl': sanitization.ɵɵsanitizeUrl,
|
||||||
'ɵɵsanitizeUrlOrResourceUrl': sanitization.ɵɵsanitizeUrlOrResourceUrl
|
'ɵɵsanitizeUrlOrResourceUrl': sanitization.ɵɵsanitizeUrlOrResourceUrl,
|
||||||
|
|
||||||
|
'ɵregisterNgModuleType': registerNgModuleType,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue