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:
Alex Rickabaugh
2018-05-31 15:50:02 -07:00
committed by Miško Hevery
parent 0f7e4fae20
commit 27bc7dcb43
69 changed files with 1884 additions and 607 deletions

View File

@ -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}`);

View File

@ -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,

View File

@ -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;
}