feat(ivy): ngtsc compiles @Component, @Directive, @NgModule (#24427)
This change supports compilation of components, directives, and modules within ngtsc. Support is not complete, but is enough to compile and test //packages/core/test/bundling/todo in full AOT mode. Code size benefits are not yet achieved as //packages/core itself does not get compiled, and some decorators (e.g. @Input) are not stripped, leading to unwanted code being retained by the tree-shaker. This will be improved in future commits. PR Close #24427
This commit is contained in:

committed by
Miško Hevery

parent
0f7e4fae20
commit
27bc7dcb43
@ -47,7 +47,9 @@ export function compileComponent(type: Type<any>, metadata: Component): Promise<
|
||||
const constantPool = new ConstantPool();
|
||||
|
||||
// Parse the template and check for errors.
|
||||
const template = parseTemplate(templateStr, `ng://${type.name}/template.html`);
|
||||
const template = parseTemplate(templateStr, `ng://${type.name}/template.html`, {
|
||||
preserveWhitespaces: metadata.preserveWhitespaces || false,
|
||||
});
|
||||
if (template.errors !== undefined) {
|
||||
const errors = template.errors.map(err => err.toString()).join(', ');
|
||||
throw new Error(`Errors during JIT compilation of template for ${type.name}: ${errors}`);
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
import {defineInjectable, defineInjector,} from '../../di/defs';
|
||||
import {inject} from '../../di/injector';
|
||||
import {defineNgModule} from '../../metadata/ng_module';
|
||||
import * as r3 from '../index';
|
||||
|
||||
|
||||
@ -22,7 +21,7 @@ export const angularCoreEnv: {[name: string]: Function} = {
|
||||
'ɵdefineDirective': r3.defineDirective,
|
||||
'defineInjectable': defineInjectable,
|
||||
'defineInjector': defineInjector,
|
||||
'ɵdefineNgModule': defineNgModule,
|
||||
'ɵdefineNgModule': r3.defineNgModule,
|
||||
'ɵdefinePipe': r3.definePipe,
|
||||
'ɵdirectiveInject': r3.directiveInject,
|
||||
'inject': inject,
|
||||
|
@ -8,9 +8,9 @@
|
||||
|
||||
import {Expression, R3NgModuleMetadata, WrappedNodeExpr, compileNgModule as compileR3NgModule, jitExpression} from '@angular/compiler';
|
||||
|
||||
import {ModuleWithProviders, NgModule, NgModuleDef, NgModuleTransitiveScopes} from '../../metadata/ng_module';
|
||||
import {ModuleWithProviders, NgModule, NgModuleDefInternal, NgModuleTransitiveScopes} from '../../metadata/ng_module';
|
||||
import {Type} from '../../type';
|
||||
import {ComponentDef} from '../interfaces/definition';
|
||||
import {ComponentDefInternal} from '../interfaces/definition';
|
||||
|
||||
import {angularCoreEnv} from './environment';
|
||||
import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF, NG_MODULE_DEF, NG_PIPE_DEF} from './fields';
|
||||
@ -48,7 +48,8 @@ export function compileNgModule(type: Type<any>, ngModule: NgModule): void {
|
||||
if (declaration.hasOwnProperty(NG_COMPONENT_DEF)) {
|
||||
// An `ngComponentDef` field exists - go ahead and patch the component directly.
|
||||
patchComponentDefWithScope(
|
||||
(declaration as Type<any>& {ngComponentDef: ComponentDef<any>}).ngComponentDef, type);
|
||||
(declaration as Type<any>& {ngComponentDef: ComponentDefInternal<any>}).ngComponentDef,
|
||||
type);
|
||||
} else if (
|
||||
!declaration.hasOwnProperty(NG_DIRECTIVE_DEF) && !declaration.hasOwnProperty(NG_PIPE_DEF)) {
|
||||
// Set `ngSelectorScope` for future reference when the component compilation finishes.
|
||||
@ -61,7 +62,8 @@ export function compileNgModule(type: Type<any>, ngModule: NgModule): void {
|
||||
* Patch the definition of a component with directives and pipes from the compilation scope of
|
||||
* a given module.
|
||||
*/
|
||||
export function patchComponentDefWithScope<C, M>(componentDef: ComponentDef<C>, module: Type<M>) {
|
||||
export function patchComponentDefWithScope<C, M>(
|
||||
componentDef: ComponentDefInternal<C>, module: Type<M>) {
|
||||
componentDef.directiveDefs = () => Array.from(transitiveScopesFor(module).compilation.directives)
|
||||
.map(dir => dir.ngDirectiveDef || dir.ngComponentDef)
|
||||
.filter(def => !!def);
|
||||
@ -113,7 +115,7 @@ export function transitiveScopesFor<T>(moduleType: Type<T>): NgModuleTransitiveS
|
||||
def.imports.forEach(<I>(imported: Type<I>) => {
|
||||
let importedTyped = imported as Type<I>& {
|
||||
// If imported is an @NgModule:
|
||||
ngModuleDef?: NgModuleDef<I>;
|
||||
ngModuleDef?: NgModuleDefInternal<I>;
|
||||
};
|
||||
|
||||
if (!isNgModule<I>(importedTyped)) {
|
||||
@ -132,7 +134,7 @@ export function transitiveScopesFor<T>(moduleType: Type<T>): NgModuleTransitiveS
|
||||
// Components, Directives, NgModules, and Pipes can all be exported.
|
||||
ngComponentDef?: any;
|
||||
ngDirectiveDef?: any;
|
||||
ngModuleDef?: NgModuleDef<E>;
|
||||
ngModuleDef?: NgModuleDefInternal<E>;
|
||||
ngPipeDef?: any;
|
||||
};
|
||||
|
||||
@ -188,6 +190,6 @@ function isModuleWithProviders(value: any): value is ModuleWithProviders {
|
||||
return (value as{ngModule?: any}).ngModule !== undefined;
|
||||
}
|
||||
|
||||
function isNgModule<T>(value: Type<T>): value is Type<T>&{ngModuleDef: NgModuleDef<T>} {
|
||||
return (value as{ngModuleDef?: NgModuleDef<T>}).ngModuleDef !== undefined;
|
||||
function isNgModule<T>(value: Type<T>): value is Type<T>&{ngModuleDef: NgModuleDefInternal<T>} {
|
||||
return (value as{ngModuleDef?: NgModuleDefInternal<T>}).ngModuleDef !== undefined;
|
||||
}
|
||||
|
Reference in New Issue
Block a user