Skip to content

Commit ef9cb6a

Browse files
ocombekara
authored andcommitted
perf(ivy): chain multiple i18nExp calls (angular#31258)
Implement function chaining for `i18nExp` to reduce the output size. FW-1391 #resolve PR Close angular#31258
1 parent 3846192 commit ef9cb6a

File tree

4 files changed

+54
-76
lines changed

4 files changed

+54
-76
lines changed

packages/compiler-cli/test/compliance/r3_view_compiler_i18n_spec.ts

Lines changed: 20 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -464,14 +464,10 @@ describe('i18n support in the view compiler', () => {
464464
$r3$.ɵɵelementEnd();
465465
}
466466
if (rf & 2) {
467-
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(1, 6, ctx.valueA));
468-
$r3$.ɵɵi18nExp(ctx.valueB);
467+
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(1, 6, ctx.valueA))(ctx.valueB);
469468
$r3$.ɵɵi18nApply(2);
470469
$r3$.ɵɵselect(3);
471-
$r3$.ɵɵi18nExp(ctx.valueA);
472-
$r3$.ɵɵi18nExp(ctx.valueB);
473-
$r3$.ɵɵi18nExp(ctx.valueA + ctx.valueB);
474-
$r3$.ɵɵi18nExp(ctx.valueC);
470+
$r3$.ɵɵi18nExp(ctx.valueA)(ctx.valueB)(ctx.valueA + ctx.valueB)(ctx.valueC);
475471
$r3$.ɵɵi18nApply(4);
476472
}
477473
}
@@ -690,14 +686,10 @@ describe('i18n support in the view compiler', () => {
690686
$r3$.ɵɵelementEnd();
691687
}
692688
if (rf & 2) {
693-
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(1, 6, ctx.valueA));
694-
$r3$.ɵɵi18nExp(ctx.valueB);
689+
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(1, 6, ctx.valueA))(ctx.valueB);
695690
$r3$.ɵɵi18nApply(2);
696691
$r3$.ɵɵselect(3);
697-
$r3$.ɵɵi18nExp(ctx.valueA);
698-
$r3$.ɵɵi18nExp(ctx.valueB);
699-
$r3$.ɵɵi18nExp(ctx.valueA + ctx.valueB);
700-
$r3$.ɵɵi18nExp(ctx.valueC);
692+
$r3$.ɵɵi18nExp(ctx.valueA)(ctx.valueB)(ctx.valueA + ctx.valueB)(ctx.valueC);
701693
$r3$.ɵɵi18nApply(4);
702694
}
703695
}
@@ -1054,8 +1046,7 @@ describe('i18n support in the view compiler', () => {
10541046
}
10551047
if (rf & 2) {
10561048
$r3$.ɵɵselect(1);
1057-
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(2, 2, ctx.valueA));
1058-
$r3$.ɵɵi18nExp(ctx.valueA == null ? null : ctx.valueA.a == null ? null : ctx.valueA.a.b);
1049+
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(2, 2, ctx.valueA))(ctx.valueA == null ? null : ctx.valueA.a == null ? null : ctx.valueA.a.b);
10591050
$r3$.ɵɵi18nApply(1);
10601051
}
10611052
}
@@ -1224,8 +1215,7 @@ describe('i18n support in the view compiler', () => {
12241215
$r3$.ɵɵi18nExp(ctx.one);
12251216
$r3$.ɵɵi18nApply(1);
12261217
$r3$.ɵɵselect(4);
1227-
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(5, 3, ctx.two));
1228-
$r3$.ɵɵi18nExp(ctx.nestedInBlockTwo);
1218+
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(5, 3, ctx.two))(ctx.nestedInBlockTwo);
12291219
$r3$.ɵɵi18nApply(4);
12301220
}
12311221
}
@@ -1335,8 +1325,7 @@ describe('i18n support in the view compiler', () => {
13351325
}
13361326
if (rf & 2) {
13371327
$r3$.ɵɵselect(2);
1338-
$r3$.ɵɵi18nExp(ctx.valueB);
1339-
$r3$.ɵɵi18nExp(ctx.valueC);
1328+
$r3$.ɵɵi18nExp(ctx.valueB)(ctx.valueC);
13401329
$r3$.ɵɵi18nApply(3);
13411330
$r3$.ɵɵi18nExp(ctx.valueA);
13421331
$r3$.ɵɵi18nApply(1);
@@ -1402,8 +1391,7 @@ describe('i18n support in the view compiler', () => {
14021391
if (rf & 2) {
14031392
const $ctx_r0$ = $r3$.ɵɵnextContext();
14041393
$r3$.ɵɵselect(2);
1405-
$r3$.ɵɵi18nExp($ctx_r0$.valueA);
1406-
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(4, 2, $ctx_r0$.valueB));
1394+
$r3$.ɵɵi18nExp($ctx_r0$.valueA)($r3$.ɵɵpipeBind1(4, 2, $ctx_r0$.valueB));
14071395
$r3$.ɵɵi18nApply(2);
14081396
}
14091397
}
@@ -1527,8 +1515,7 @@ describe('i18n support in the view compiler', () => {
15271515
}
15281516
if (rf & 2) {
15291517
const $ctx_r2$ = $r3$.ɵɵnextContext(2);
1530-
$r3$.ɵɵi18nExp($ctx_r2$.valueC);
1531-
$r3$.ɵɵi18nExp($ctx_r2$.valueD);
1518+
$r3$.ɵɵi18nExp($ctx_r2$.valueC)($ctx_r2$.valueD);
15321519
$r3$.ɵɵi18nApply(0);
15331520
}
15341521
}
@@ -1547,8 +1534,7 @@ describe('i18n support in the view compiler', () => {
15471534
const $ctx_r0$ = $r3$.ɵɵnextContext();
15481535
$r3$.ɵɵselect(4);
15491536
$r3$.ɵɵproperty("ngIf", $ctx_r0$.exists);
1550-
$r3$.ɵɵi18nExp($ctx_r0$.valueA);
1551-
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(3, 3, $ctx_r0$.valueB));
1537+
$r3$.ɵɵi18nExp($ctx_r0$.valueA)($r3$.ɵɵpipeBind1(3, 3, $ctx_r0$.valueB));
15521538
$r3$.ɵɵi18nApply(0);
15531539
}
15541540
}
@@ -1596,8 +1582,7 @@ describe('i18n support in the view compiler', () => {
15961582
}
15971583
if (rf & 2) {
15981584
const $ctx_r1$ = $r3$.ɵɵnextContext();
1599-
$r3$.ɵɵi18nExp($ctx_r1$.valueE + $ctx_r1$.valueF);
1600-
$r3$.ɵɵi18nExp($r3$.ɵɵpipeBind1(3, 2, $ctx_r1$.valueG));
1585+
$r3$.ɵɵi18nExp($ctx_r1$.valueE + $ctx_r1$.valueF)($r3$.ɵɵpipeBind1(3, 2, $ctx_r1$.valueG));
16011586
$r3$.ɵɵi18nApply(0);
16021587
}
16031588
}
@@ -2554,8 +2539,7 @@ describe('i18n support in the view compiler', () => {
25542539
if (rf & 2) {
25552540
const $ctx_r1$ = $r3$.ɵɵnextContext();
25562541
$r3$.ɵɵselect(2);
2557-
$r3$.ɵɵi18nExp($ctx_r1$.count);
2558-
$r3$.ɵɵi18nExp($ctx_r1$.count);
2542+
$r3$.ɵɵi18nExp($ctx_r1$.count)($ctx_r1$.count);
25592543
$r3$.ɵɵi18nApply(2);
25602544
}
25612545
}
@@ -2615,8 +2599,7 @@ describe('i18n support in the view compiler', () => {
26152599
}
26162600
if (rf & 2) {
26172601
$r3$.ɵɵselect(1);
2618-
$r3$.ɵɵi18nExp(ctx.age);
2619-
$r3$.ɵɵi18nExp(ctx.other);
2602+
$r3$.ɵɵi18nExp(ctx.age)(ctx.other);
26202603
$r3$.ɵɵi18nApply(1);
26212604
}
26222605
}
@@ -2742,8 +2725,7 @@ describe('i18n support in the view compiler', () => {
27422725
}
27432726
if (rf & 2) {
27442727
$r3$.ɵɵselect(1);
2745-
$r3$.ɵɵi18nExp(ctx.gender);
2746-
$r3$.ɵɵi18nExp(ctx.ageA + ctx.ageB + ctx.ageC);
2728+
$r3$.ɵɵi18nExp(ctx.gender)(ctx.ageA + ctx.ageB + ctx.ageC);
27472729
$r3$.ɵɵi18nApply(1);
27482730
}
27492731
}
@@ -2808,8 +2790,7 @@ describe('i18n support in the view compiler', () => {
28082790
}
28092791
if (rf & 2) {
28102792
$r3$.ɵɵselect(1);
2811-
$r3$.ɵɵi18nExp(ctx.gender);
2812-
$r3$.ɵɵi18nExp(ctx.age);
2793+
$r3$.ɵɵi18nExp(ctx.gender)(ctx.age);
28132794
$r3$.ɵɵi18nApply(1);
28142795
}
28152796
}
@@ -2914,8 +2895,7 @@ describe('i18n support in the view compiler', () => {
29142895
if (rf & 2) {
29152896
$r3$.ɵɵselect(3);
29162897
$r3$.ɵɵproperty("ngIf", ctx.visible);
2917-
$r3$.ɵɵi18nExp(ctx.gender);
2918-
$r3$.ɵɵi18nExp(ctx.gender);
2898+
$r3$.ɵɵi18nExp(ctx.gender)(ctx.gender);
29192899
$r3$.ɵɵi18nApply(1);
29202900
}
29212901
}
@@ -2962,8 +2942,7 @@ describe('i18n support in the view compiler', () => {
29622942
}
29632943
if (rf & 2) {
29642944
$r3$.ɵɵselect(1);
2965-
$r3$.ɵɵi18nExp(ctx.age);
2966-
$r3$.ɵɵi18nExp(ctx.gender);
2945+
$r3$.ɵɵi18nExp(ctx.age)(ctx.gender);
29672946
$r3$.ɵɵi18nApply(1);
29682947
}
29692948
}
@@ -3132,8 +3111,7 @@ describe('i18n support in the view compiler', () => {
31323111
}
31333112
if (rf & 2) {
31343113
const $ctx_r0$ = $r3$.ɵɵnextContext();
3135-
$r3$.ɵɵi18nExp($ctx_r0$.age);
3136-
$r3$.ɵɵi18nExp($ctx_r0$.otherAge);
3114+
$r3$.ɵɵi18nExp($ctx_r0$.age)($ctx_r0$.otherAge);
31373115
$r3$.ɵɵi18nApply(0);
31383116
}
31393117
}
@@ -3151,9 +3129,7 @@ describe('i18n support in the view compiler', () => {
31513129
if (rf & 2) {
31523130
$r3$.ɵɵselect(2);
31533131
$r3$.ɵɵproperty("ngIf", ctx.ageVisible);
3154-
$r3$.ɵɵi18nExp(ctx.gender);
3155-
$r3$.ɵɵi18nExp(ctx.weight);
3156-
$r3$.ɵɵi18nExp(ctx.height);
3132+
$r3$.ɵɵi18nExp(ctx.gender)(ctx.weight)(ctx.height);
31573133
$r3$.ɵɵi18nApply(1);
31583134
}
31593135
}
@@ -3204,10 +3180,7 @@ describe('i18n support in the view compiler', () => {
32043180
}
32053181
if (rf & 2) {
32063182
$r3$.ɵɵselect(1);
3207-
$r3$.ɵɵi18nExp(ctx.gender);
3208-
$r3$.ɵɵi18nExp(ctx.weight);
3209-
$r3$.ɵɵi18nExp(ctx.height);
3210-
$r3$.ɵɵi18nExp(ctx.age);
3183+
$r3$.ɵɵi18nExp(ctx.gender)(ctx.weight)(ctx.height)(ctx.age);
32113184
$r3$.ɵɵi18nApply(1);
32123185
}
32133186
}

packages/compiler/src/render3/view/template.ts

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -456,10 +456,14 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
456456
// setup accumulated bindings
457457
const {index, bindings} = this.i18n;
458458
if (bindings.size) {
459+
const chainBindings: ChainableBindingInstruction[] = [];
459460
bindings.forEach(binding => {
460-
this.updateInstruction(
461-
index, span, R3.i18nExp, () => [this.convertPropertyBinding(binding)]);
461+
chainBindings.push({
462+
sourceSpan: span,
463+
value: () => this.convertPropertyBinding(binding)
464+
});
462465
});
466+
this.updateInstructionChain(index, R3.i18nExp, chainBindings);
463467
this.updateInstruction(index, span, R3.i18nApply, [o.literal(index)]);
464468
}
465469
if (!selfClosing) {
@@ -641,6 +645,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
641645
if (i18nAttrs.length) {
642646
let hasBindings: boolean = false;
643647
const i18nAttrArgs: o.Expression[] = [];
648+
const bindings: ChainableBindingInstruction[] = [];
644649
i18nAttrs.forEach(attr => {
645650
const message = attr.i18n !as i18n.Message;
646651
if (attr instanceof t.TextAttribute) {
@@ -654,13 +659,17 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
654659
i18nAttrArgs.push(o.literal(attr.name), this.i18nTranslate(message, params));
655660
converted.expressions.forEach(expression => {
656661
hasBindings = true;
657-
this.updateInstruction(
658-
elementIndex, element.sourceSpan, R3.i18nExp,
659-
() => [this.convertExpressionBinding(expression)]);
662+
bindings.push({
663+
sourceSpan: element.sourceSpan,
664+
value: () => this.convertExpressionBinding(expression)
665+
});
660666
});
661667
}
662668
}
663669
});
670+
if (bindings.length) {
671+
this.updateInstructionChain(elementIndex, R3.i18nExp, bindings);
672+
}
664673
if (i18nAttrArgs.length) {
665674
const index: o.Expression = o.literal(this.allocateDataSlot());
666675
const args = this.constantPool.getConstLiteral(o.literalArr(i18nAttrArgs), true);
@@ -733,7 +742,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
733742

734743
propertyBindings.push({
735744
name: prepareSyntheticPropertyName(input.name),
736-
input,
745+
sourceSpan: input.sourceSpan,
737746
value: () => hasValue ? this.convertPropertyBinding(value) : emptyValueBindInstruction
738747
});
739748
} else {
@@ -771,7 +780,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
771780
// [prop]="value"
772781
// Collect all the properties so that we can chain into a single function at the end.
773782
propertyBindings.push(
774-
{name: attrName, input, value: () => this.convertPropertyBinding(value), params});
783+
{name: attrName, sourceSpan: input.sourceSpan, value: () => this.convertPropertyBinding(value), params});
775784
}
776785
} else if (inputType === BindingType.Attribute) {
777786
if (value instanceof Interpolation && getInterpolationArgsLength(value) > 1) {
@@ -785,7 +794,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
785794
// Collect the attribute bindings so that they can be chained at the end.
786795
attributeBindings.push({
787796
name: attrName,
788-
input,
797+
sourceSpan: input.sourceSpan,
789798
value: () => this.convertPropertyBinding(boundValue), params
790799
});
791800
}
@@ -830,18 +839,6 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
830839
}
831840
}
832841

833-
/**
834-
* Adds an update instruction for a bound property or attribute, such as `[prop]="value"` or
835-
* `[attr.title]="value"`
836-
*/
837-
boundUpdateInstruction(
838-
instruction: o.ExternalReference, elementIndex: number, attrName: string,
839-
input: t.BoundAttribute, value: any, params: any[]) {
840-
this.updateInstruction(elementIndex, input.sourceSpan, instruction, () => {
841-
return [o.literal(attrName), this.convertPropertyBinding(value), ...params];
842-
});
843-
}
844-
845842
/**
846843
* Adds an update instruction for an interpolated property or attribute, such as
847844
* `prop="{{value}}"` or `attr.title="{{value}}"`
@@ -1042,7 +1039,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
10421039
if (value !== undefined) {
10431040
this.allocateBindingSlots(value);
10441041
propertyBindings.push(
1045-
{name: input.name, input, value: () => this.convertPropertyBinding(value)});
1042+
{name: input.name, sourceSpan: input.sourceSpan, value: () => this.convertPropertyBinding(value)});
10461043
}
10471044
}
10481045
});
@@ -1093,12 +1090,17 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
10931090

10941091
private updateInstructionChain(
10951092
nodeIndex: number, reference: o.ExternalReference, bindings: ChainableBindingInstruction[]) {
1096-
const span = bindings.length ? bindings[0].input.sourceSpan : null;
1093+
const span = bindings.length ? bindings[0].sourceSpan : null;
10971094

10981095
this.addSelectInstructionIfNecessary(nodeIndex, span);
10991096
this._updateCodeFns.push(() => {
1100-
const calls = bindings.map(
1101-
property => [o.literal(property.name), property.value(), ...(property.params || [])]);
1097+
const calls = bindings.map(property => {
1098+
const fnParams = [property.value(), ...(property.params || [])];
1099+
if (property.name) {
1100+
fnParams.unshift(o.literal(property.name));
1101+
}
1102+
return fnParams;
1103+
});
11021104

11031105
return chainedInstruction(span, reference, calls).toStmt();
11041106
});
@@ -2027,8 +2029,8 @@ function hasTextChildrenOnly(children: t.Node[]): boolean {
20272029
}
20282030

20292031
interface ChainableBindingInstruction {
2030-
name: string;
2031-
input: t.BoundAttribute;
2032+
name?: string;
2033+
sourceSpan: ParseSourceSpan|null;
20322034
value: () => o.Expression;
20332035
params?: any[];
20342036
}

packages/core/src/render3/i18n.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {assertDataInRange, assertDefined, assertEqual, assertGreaterThan} from '
1616
import {attachPatchData} from './context_discovery';
1717
import {bind, setDelayProjection, ɵɵload} from './instructions/all';
1818
import {attachI18nOpCodesDebug} from './instructions/lview_debug';
19-
import {allocExpando, elementAttributeInternal, elementPropertyInternal, getOrCreateTNode, setInputsForProperty, textBindingInternal} from './instructions/shared';
19+
import {allocExpando, elementAttributeInternal, elementPropertyInternal, getOrCreateTNode, setInputsForProperty, textBindingInternal, TsickleIssue1009} from './instructions/shared';
2020
import {LContainer, NATIVE} from './interfaces/container';
2121
import {COMMENT_MARKER, ELEMENT_MARKER, I18nMutateOpCode, I18nMutateOpCodes, I18nUpdateOpCode, I18nUpdateOpCodes, IcuType, TI18n, TIcu} from './interfaces/i18n';
2222
import {TElementNode, TIcuContainerNode, TNode, TNodeFlags, TNodeType, TProjectionNode} from './interfaces/node';
@@ -1012,16 +1012,19 @@ let shiftsCounter = 0;
10121012
* update the translated nodes.
10131013
*
10141014
* @param value The binding's value
1015+
* @returns This function returns itself so that it may be chained
1016+
* (e.g. `i18nExp(ctx.name)(ctx.title)`)
10151017
*
10161018
* @codeGenApi
10171019
*/
1018-
export function ɵɵi18nExp<T>(value: T): void {
1020+
export function ɵɵi18nExp<T>(value: T): TsickleIssue1009 {
10191021
const lView = getLView();
10201022
const expression = bind(lView, value);
10211023
if (expression !== NO_CHANGE) {
10221024
changeMask = changeMask | (1 << shiftsCounter);
10231025
}
10241026
shiftsCounter++;
1027+
return ɵɵi18nExp;
10251028
}
10261029

10271030
/**

tools/public_api_guard/core/core.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -851,7 +851,7 @@ export declare function ɵɵi18nAttributes(index: number, values: string[]): voi
851851

852852
export declare function ɵɵi18nEnd(): void;
853853

854-
export declare function ɵɵi18nExp<T>(value: T): void;
854+
export declare function ɵɵi18nExp<T>(value: T): TsickleIssue1009;
855855

856856
/** @deprecated */
857857
export declare function ɵɵi18nLocalize(input: string, placeholders?: {

0 commit comments

Comments
 (0)