From 764e90f9bb0dfdec164bb5db515891f8470c07fa Mon Sep 17 00:00:00 2001 From: Tobias Bosch Date: Mon, 20 Mar 2017 15:26:06 -0700 Subject: [PATCH] =?UTF-8?q?fix(compiler):=20don=E2=80=99t=20call=20`check`?= =?UTF-8?q?=20if=20we=20don=E2=80=99t=20need=20to=20(#15322)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a directive has not bindings nor has a `ngDoCheck` / `ngOnInit` lifecycle hook, don’t generate a `check` call. This does not have an impact on the behavior, but produces less code. PR Close #15322 --- .../src/view_compiler/view_compiler.ts | 21 +++++++++----- packages/compiler/test/aot/compiler_spec.ts | 29 +++++++++++++++++++ 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/packages/compiler/src/view_compiler/view_compiler.ts b/packages/compiler/src/view_compiler/view_compiler.ts index dbf2869ba6..2651eee983 100644 --- a/packages/compiler/src/view_compiler/view_compiler.ts +++ b/packages/compiler/src/view_compiler/view_compiler.ts @@ -108,6 +108,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { private nodes: (() => { sourceSpan: ParseSourceSpan, nodeDef: o.Expression, + directive?: CompileTypeMetadata, updateDirectives?: UpdateExpression[], updateRenderer?: UpdateExpression[] })[] = []; @@ -582,6 +583,7 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { outputDefs.length ? new o.LiteralMapExpr(outputDefs) : o.NULL_EXPR ]), updateDirectives: updateDirectiveExpressions, + directive: dirAst.directive.type, }); return {hostBindings, hostEvents}; @@ -790,13 +792,14 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { const updateRendererStmts: o.Statement[] = []; const updateDirectivesStmts: o.Statement[] = []; const nodeDefExprs = this.nodes.map((factory, nodeIndex) => { - const {nodeDef, updateDirectives, updateRenderer, sourceSpan} = factory(); + const {nodeDef, directive, updateDirectives, updateRenderer, sourceSpan} = factory(); if (updateRenderer) { - updateRendererStmts.push(...createUpdateStatements(nodeIndex, sourceSpan, updateRenderer)); + updateRendererStmts.push( + ...createUpdateStatements(nodeIndex, sourceSpan, updateRenderer, null)); } if (updateDirectives) { updateDirectivesStmts.push( - ...createUpdateStatements(nodeIndex, sourceSpan, updateDirectives)); + ...createUpdateStatements(nodeIndex, sourceSpan, updateDirectives, directive)); } // We use a comma expression to call the log function before // the nodeDef function, but still use the result of the nodeDef function @@ -807,8 +810,8 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { return {updateRendererStmts, updateDirectivesStmts, nodeDefExprs}; function createUpdateStatements( - nodeIndex: number, sourceSpan: ParseSourceSpan, - expressions: UpdateExpression[]): o.Statement[] { + nodeIndex: number, sourceSpan: ParseSourceSpan, expressions: UpdateExpression[], + directive: CompileTypeMetadata): o.Statement[] { const updateStmts: o.Statement[] = []; const exprs = expressions.map(({sourceSpan, context, value}) => { const bindingId = `${updateBindingCount++}`; @@ -819,8 +822,12 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver { ...stmts.map(stmt => o.applySourceSpanToStatementIfNeeded(stmt, sourceSpan))); return o.applySourceSpanToExpressionIfNeeded(currValExpr, sourceSpan); }); - updateStmts.push(o.applySourceSpanToStatementIfNeeded( - callCheckStmt(nodeIndex, exprs).toStmt(), sourceSpan)); + if (expressions.length || + (directive && (directive.lifecycleHooks.indexOf(LifecycleHooks.DoCheck) !== -1 || + directive.lifecycleHooks.indexOf(LifecycleHooks.OnInit) !== -1))) { + updateStmts.push(o.applySourceSpanToStatementIfNeeded( + callCheckStmt(nodeIndex, exprs).toStmt(), sourceSpan)); + } return updateStmts; } } diff --git a/packages/compiler/test/aot/compiler_spec.ts b/packages/compiler/test/aot/compiler_spec.ts index 5c40d07455..409a5bc7be 100644 --- a/packages/compiler/test/aot/compiler_spec.ts +++ b/packages/compiler/test/aot/compiler_spec.ts @@ -339,6 +339,35 @@ describe('compiler (unbundled Angular)', () => { }); })); }); + + describe('generated templates', () => { + it('should not call `check` for directives without bindings nor ngDoCheck/ngOnInit', + async(() => { + const FILES: MockData = { + app: { + 'app.ts': ` + import { NgModule, Component } from '@angular/core'; + + @Component({ template: '' }) + export class AppComponent {} + + @NgModule({ declarations: [ AppComponent ] }) + export class AppModule { } + ` + } + }; + const host = new MockCompilerHost(['/app/app.ts'], FILES, angularFiles); + const aotHost = new MockAotCompilerHost(host); + const genFilePreamble = '/* Hello world! */'; + compile(host, aotHost, expectNoDiagnostics, expectNoDiagnostics, {genFilePreamble}) + .then((generatedFiles) => { + const genFile = generatedFiles.find( + gf => gf.srcFileUrl === '/app/app.ts' && gf.genFileUrl.endsWith('.ts')); + expect(genFile.source).not.toContain('check('); + }); + + })); + }); }); describe('compiler (bundled Angular)', () => {