From cae01dae1ba0cf4edff4ef758ce4c24f0dba2070 Mon Sep 17 00:00:00 2001 From: Dylan Hunn Date: Fri, 25 Aug 2023 14:06:21 -0700 Subject: [PATCH] refactor(compiler): Support class and style attrs in host bindings (#51498) The template pipeline is already capable of parsing and processing class and style attributes on templates. We now extend that functionality to host bindings. The parser, for some reason, splits out class and style attributes into a `specialAttributes` field. We merge them back into the main attributes map, and allow the template pipeline to process them normally. PR Close #51498 --- .../host_bindings/TEST_CASES.json | 3 +-- .../host_bindings/TEST_CASES.json | 3 +-- .../compiler/src/render3/view/compiler.ts | 20 ++++++++++++++----- .../src/template/pipeline/src/emit.ts | 1 + .../src/phases/parse_extracted_styles.ts | 4 ++-- 5 files changed, 20 insertions(+), 11 deletions(-) diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/TEST_CASES.json b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/TEST_CASES.json index c1124a924e2..d577608c6cf 100644 --- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/TEST_CASES.json +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/host_bindings/TEST_CASES.json @@ -84,8 +84,7 @@ "host_attributes_with_classes_and_styles.js" ] } - ], - "skipForTemplatePipeline": true + ] }, { "description": "should chain multiple host property bindings into a single instruction", diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_styling/host_bindings/TEST_CASES.json b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_styling/host_bindings/TEST_CASES.json index 429ac636a41..4601c866413 100644 --- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_styling/host_bindings/TEST_CASES.json +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_styling/host_bindings/TEST_CASES.json @@ -13,8 +13,7 @@ "static_and_dynamic.js" ] } - ], - "skipForTemplatePipeline": true + ] }, { "description": "should generate style/class instructions for multiple host binding definitions", diff --git a/packages/compiler/src/render3/view/compiler.ts b/packages/compiler/src/render3/view/compiler.ts index a30fe6d1c39..88f860a1cf9 100644 --- a/packages/compiler/src/render3/view/compiler.ts +++ b/packages/compiler/src/render3/view/compiler.ts @@ -566,15 +566,24 @@ function createHostBindingsFunction( const bindings = bindingParser.createBoundHostProperties(hostBindingsMetadata.properties, typeSourceSpan); - // Calculate host event bindings const eventBindings = bindingParser.createDirectiveHostEventAsts(hostBindingsMetadata.listeners, typeSourceSpan); if (USE_TEMPLATE_PIPELINE) { - // TODO: host binding metadata is not yet parsed in the template pipeline, so we need to extract - // that code from below. Then, we will ingest a `HostBindingJob`, and run the template pipeline - // phases. + // The parser for host bindings treats class and style attributes specially -- they are + // extracted into these separate fields. This is not the case for templates, so the compiler can + // actually already handle these special attributes internally. Therefore, we just drop them + // into the attributes map. + if (hostBindingsMetadata.specialAttributes.styleAttr) { + hostBindingsMetadata.attributes.style = + o.literal(hostBindingsMetadata.specialAttributes.styleAttr); + } + if (hostBindingsMetadata.specialAttributes.classAttr) { + hostBindingsMetadata.attributes.class = + o.literal(hostBindingsMetadata.specialAttributes.classAttr); + } + const hostJob = ingestHostBinding( { componentName: name, @@ -585,11 +594,12 @@ function createHostBindingsFunction( bindingParser, constantPool); transformHostBinding(hostJob); + definitionMap.set('hostAttrs', hostJob.root.attributes); + const varCount = hostJob.root.vars; if (varCount !== null && varCount > 0) { definitionMap.set('hostVars', o.literal(varCount)); } - definitionMap.set('hostAttrs', hostJob.root.attributes); return emitHostBindingFunction(hostJob); } diff --git a/packages/compiler/src/template/pipeline/src/emit.ts b/packages/compiler/src/template/pipeline/src/emit.ts index 368298d259f..03ea4580ba7 100644 --- a/packages/compiler/src/template/pipeline/src/emit.ts +++ b/packages/compiler/src/template/pipeline/src/emit.ts @@ -110,6 +110,7 @@ export function transformHostBinding(job: HostBindingCompilationJob): void { phaseStyleBindingSpecialization(job); phaseBindingSpecialization(job); phaseAttributeExtraction(job); + phaseParseExtractedStyles(job); phasePureLiteralStructures(job); phaseConstCollection(job); phaseNullishCoalescing(job); diff --git a/packages/compiler/src/template/pipeline/src/phases/parse_extracted_styles.ts b/packages/compiler/src/template/pipeline/src/phases/parse_extracted_styles.ts index 2428deb5729..ef834d31ef5 100644 --- a/packages/compiler/src/template/pipeline/src/phases/parse_extracted_styles.ts +++ b/packages/compiler/src/template/pipeline/src/phases/parse_extracted_styles.ts @@ -9,13 +9,13 @@ import * as o from '../../../../output/output_ast'; import {parse as parseStyle} from '../../../../render3/view/style_parser'; import * as ir from '../../ir'; -import {ComponentCompilationJob} from '../compilation'; +import type {CompilationJob} from '../compilation'; /** * Parses extracted style and class attributes into separate ExtractedAttributeOps per style or * class property. */ -export function phaseParseExtractedStyles(cpl: ComponentCompilationJob) { +export function phaseParseExtractedStyles(cpl: CompilationJob) { for (const unit of cpl.units) { for (const op of unit.create) { if (op.kind === ir.OpKind.ExtractedAttribute && op.bindingKind === ir.BindingKind.Attribute &&