fix(compiler): don’t call `check` if we don’t need to (#15322)
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
This commit is contained in:
parent
9bf2fb4a74
commit
764e90f9bb
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)', () => {
|
||||
|
|
Loading…
Reference in New Issue