fix(ivy): don't match directives against attribute bindings (#31541)

Fixes Ivy matching directives against attribute bindings (e.g. `[attr.some-directive]="foo"`). Works by excluding attribute bindings from the attributes array during compilation. This has the added benefit of generating less code.

**Note:** My initial approach to implementing this was to have a different marker for attribute bindings so that they can be ignored when matching directives, however as I was implementing it I realized that the attributes in that array were only used for directive matching (as far as I could tell). I decided to drop the attribute bindings completely, because it results in less generated code.

PR Close #31541
This commit is contained in:
crisbeto
2019-07-13 13:34:34 +02:00
committed by Matias Niemelä
parent 9e83822679
commit 12fd06916b
6 changed files with 70 additions and 9 deletions

View File

@ -612,6 +612,41 @@ describe('compiler compliance: bindings', () => {
expectEmit(result.source, template, 'Incorrect template');
});
it('should exclude attribute bindings from the attributes array', () => {
const files: MockDirectory = {
app: {
'example.ts': `
import {Component, NgModule} from '@angular/core';
@Component({
selector: 'my-app',
template: \`<a
target="_blank"
[title]="1"
[attr.foo]="'one'"
(customEvent)="doThings()"
[attr.bar]="'two'"
[id]="2"
aria-label="link"
[attr.baz]="three"></a>\`
})
export class MyComponent {
doThings() {}
}
@NgModule({declarations: [MyComponent]})
export class MyModule {}`
}
};
const template = `
const $e0_attrs$ = ["target", "_blank", "aria-label", "link", ${AttributeMarker.Bindings}, "title", "id", "customEvent"];
`;
const result = compile(files, angularFiles);
expectEmit(result.source, template, 'Incorrect attribute array');
});
});
describe('host bindings', () => {

View File

@ -333,7 +333,7 @@ describe('i18n support in the view compiler', () => {
`;
const output = `
const $_c0$ = [${AttributeMarker.Bindings}, "title", "label"];
const $_c0$ = [3, "title"];
template: function MyComponent_Template(rf, ctx) {
if (rf & 1) {

View File

@ -520,7 +520,7 @@ describe('compiler compliance: styling', () => {
};
const template = `
const $_c0$ = [${AttributeMarker.Styles}, "opacity", "1", ${AttributeMarker.Bindings}, "style"];
const $_c0$ = [${AttributeMarker.Styles}, "opacity", "1"];
const $_c1$ = ["width", "height"];
MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({
@ -741,7 +741,7 @@ describe('compiler compliance: styling', () => {
};
const template = `
const $e0_attrs$ = [${AttributeMarker.Classes}, "grape", ${AttributeMarker.Bindings}, "class"];
const $e0_attrs$ = [${AttributeMarker.Classes}, "grape"];
const $e0_bindings$ = ["apple", "orange"];
MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({
@ -797,7 +797,7 @@ describe('compiler compliance: styling', () => {
};
const template = `
const $e0_attrs$ = [${AttributeMarker.Classes}, "foo", ${AttributeMarker.Styles}, "width", "100px", ${AttributeMarker.Bindings}, "class", "style"];
const $e0_attrs$ = [${AttributeMarker.Classes}, "foo", ${AttributeMarker.Styles}, "width", "100px"];
MyComponent.ngComponentDef = $r3$.ɵɵdefineComponent({
type: MyComponent,