From f0b28f644382006ae2607c093931ab003033ec94 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Sat, 30 May 2026 09:35:43 +0200 Subject: [PATCH] fix(compiler): move projection attributes into constants We can save some memory by moving the `attrs` passed into the `projection` instruction into the constant pool. --- .../content_projection/ng_content_fallback.js | 3 ++- .../content_projection/project_as_ng_content.js | 17 +++++++++-------- .../self_closing_structural_directives.js | 4 +++- .../src/template/pipeline/ir/src/ops/create.ts | 2 +- .../src/template/pipeline/src/instruction.ts | 2 +- .../pipeline/src/phases/const_collection.ts | 2 +- 6 files changed, 17 insertions(+), 13 deletions(-) diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_compiler_compliance/components_and_directives/content_projection/ng_content_fallback.js b/packages/compiler-cli/test/compliance/test_cases/r3_compiler_compliance/components_and_directives/content_projection/ng_content_fallback.js index c1326f4c541..1676186c500 100644 --- a/packages/compiler-cli/test/compliance/test_cases/r3_compiler_compliance/components_and_directives/content_projection/ng_content_fallback.js +++ b/packages/compiler-cli/test/compliance/test_cases/r3_compiler_compliance/components_and_directives/content_projection/ng_content_fallback.js @@ -1,5 +1,6 @@ const $_c0$ = [[["basic"]], "*", [["footer"]], [["structural"]]]; const $_c1$ = ["basic", "*", "footer", "structural"]; +const $_c2$ = ["*ngIf", "hasStructural"]; function TestComponent_ProjectionFallback_0_Template(rf, ctx) { if (rf & 1) { @@ -46,7 +47,7 @@ function TestComponent_ng_content_6_ProjectionFallback_0_Template(rf, ctx) { function TestComponent_ng_content_6_Template(rf, ctx) { if (rf & 1) { - $r3$.ɵɵprojection(0, 3, ["*ngIf", "hasStructural"], TestComponent_ng_content_6_ProjectionFallback_0_Template, 2, 0); + $r3$.ɵɵprojection(0, 3, $_c2$, TestComponent_ng_content_6_ProjectionFallback_0_Template, 2, 0); } } diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_compiler_compliance/components_and_directives/content_projection/project_as_ng_content.js b/packages/compiler-cli/test/compliance/test_cases/r3_compiler_compliance/components_and_directives/content_projection/project_as_ng_content.js index 57925a7ce7f..7bee0b065a3 100644 --- a/packages/compiler-cli/test/compliance/test_cases/r3_compiler_compliance/components_and_directives/content_projection/project_as_ng_content.js +++ b/packages/compiler-cli/test/compliance/test_cases/r3_compiler_compliance/components_and_directives/content_projection/project_as_ng_content.js @@ -1,16 +1,17 @@ -const _c0 = [[["", "card-title", ""]], [["", "card-content", ""]]]; -const _c1 = ["[card-title]", "[card-content]"]; -const _c2 = ["*"]; +const $_c0$ = [[["", "card-title", ""]], [["", "card-content", ""]]]; +const $_c1$ = ["[card-title]", "[card-content]"]; +const $_c2$ = ["*"]; +const $_c3$ = ["ngProjectAs", "[card-content]", 5, ["", "card-content", ""]]; // ... selectors: [["card"]], standalone: false, -ngContentSelectors: _c1, +ngContentSelectors: $_c1$, decls: 3, vars: 0, template: function Card_Template(rf, ctx) { if (rf & 1) { - i0.ɵɵprojectionDef(_c0); + i0.ɵɵprojectionDef($_c0$); i0.ɵɵprojection(0); i0.ɵɵtext(1, " --- "); i0.ɵɵprojection(2, 1); @@ -19,7 +20,7 @@ template: function Card_Template(rf, ctx) { // ... selectors: [["card-with-title"]], standalone: false, -ngContentSelectors: _c2, +ngContentSelectors: $_c2$, decls: 4, vars: 0, consts: [["ngProjectAs", "[card-title]", 5, ["", "card-title", ""]]], @@ -29,7 +30,7 @@ template: function CardWithTitle_Template(rf, ctx) { i0.ɵɵelementStart(0, "card")(1, "h1", 0); i0.ɵɵtext(2, "Title"); i0.ɵɵelementEnd(); - i0.ɵɵprojection(3, 0, ["ngProjectAs", "[card-content]", 5, ["", "card-content", ""]]); + i0.ɵɵprojection(3, 0, $_c3$); i0.ɵɵelementEnd(); } } @@ -44,4 +45,4 @@ template: function App_Template(rf, ctx) { i0.ɵɵtext(1, "content"); i0.ɵɵelementEnd(); } -} \ No newline at end of file +} diff --git a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_template/self_closing_structural_directives.js b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_template/self_closing_structural_directives.js index d50e6f014c1..130e9aa2419 100644 --- a/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_template/self_closing_structural_directives.js +++ b/packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_template/self_closing_structural_directives.js @@ -1,3 +1,5 @@ +const $_c1$ = ["*ngIf", "flag"]; + function MyComponent_img_2_Template(rf, ctx) { if (rf & 1) { i0.ɵɵi18nStart(0, 0, 1); @@ -34,7 +36,7 @@ function MyComponent_ng_container_5_Template(rf, ctx) { function MyComponent_ng_content_6_Template(rf, ctx) { if (rf & 1) { i0.ɵɵi18nStart(0, 0, 6); - i0.ɵɵprojection(1, 0, ["*ngIf", "flag"]); + i0.ɵɵprojection(1, 0, $_c1$); i0.ɵɵi18nEnd(); } } diff --git a/packages/compiler/src/template/pipeline/ir/src/ops/create.ts b/packages/compiler/src/template/pipeline/ir/src/ops/create.ts index 51276d58d95..2a17afa96e1 100644 --- a/packages/compiler/src/template/pipeline/ir/src/ops/create.ts +++ b/packages/compiler/src/template/pipeline/ir/src/ops/create.ts @@ -1205,7 +1205,7 @@ export interface ProjectionOp extends Op, ConsumesSlotOpTrait { projectionSlotIndex: number; - attributes: null | o.LiteralArrayExpr; + attributes: null | o.Expression; localRefs: string[]; diff --git a/packages/compiler/src/template/pipeline/src/instruction.ts b/packages/compiler/src/template/pipeline/src/instruction.ts index ac9f2d85aae..96b42703b7d 100644 --- a/packages/compiler/src/template/pipeline/src/instruction.ts +++ b/packages/compiler/src/template/pipeline/src/instruction.ts @@ -410,7 +410,7 @@ export function projectionDef(def: o.Expression | null): ir.CreateOp { export function projection( slot: number, projectionSlotIndex: number, - attributes: o.LiteralArrayExpr | null, + attributes: o.Expression | null, fallbackFnName: string | null, fallbackDecls: number | null, fallbackVars: number | null, diff --git a/packages/compiler/src/template/pipeline/src/phases/const_collection.ts b/packages/compiler/src/template/pipeline/src/phases/const_collection.ts index 1a5f2201a2b..214fc220911 100644 --- a/packages/compiler/src/template/pipeline/src/phases/const_collection.ts +++ b/packages/compiler/src/template/pipeline/src/phases/const_collection.ts @@ -45,7 +45,7 @@ export function collectElementConsts(job: CompilationJob): void { if (attributes !== undefined) { const attrArray = serializeAttributes(attributes); if (attrArray.entries.length > 0) { - op.attributes = attrArray; + op.attributes = job.pool.getConstLiteral(attrArray, true); } } } else if (ir.isElementOrContainerOp(op)) {