mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
perf(compiler): chain element start/end instructions (#44994)
In templates with several levels of nested nodes, it's common for several `elementStart`/`elementEnd` instructions to show up in a row which can be optimized away. These changes add chaining support for `elementStart`, `elementEnd`, `elementContainerStart` and `elementContainerEnd` to shave off some bytes when possible. PR Close #44994
This commit is contained in:
committed by
Dylan Hunn
parent
8f1f35b973
commit
1b91e1049e
+1
-2
@@ -10,8 +10,7 @@ MyApp.ɵcmp = /*@__PURE__*/ $r3$.ɵɵdefineComponent({
|
||||
consts: [[__AttributeMarker.Bindings__, "dir"]],
|
||||
template: function MyApp_Template(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵɵelement(0, "div", 0);
|
||||
$r3$.ɵɵelement(1, "div", 0);
|
||||
$r3$.ɵɵelement(0, "div", 0)(1, "div", 0);
|
||||
}
|
||||
if (rf & 2) {
|
||||
$r3$.ɵɵproperty("dir", $r3$.ɵɵpureFunction0(2, $c0$));
|
||||
|
||||
+1
-2
@@ -6,8 +6,7 @@ SimpleLayout.ɵcmp = /*@__PURE__*/ $r3$.ɵɵdefineComponent({
|
||||
consts: [[__AttributeMarker.Bindings__, "name"]],
|
||||
template: function SimpleLayout_Template(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵɵelement(0, "lifecycle-comp", 0);
|
||||
$r3$.ɵɵelement(1, "lifecycle-comp", 0);
|
||||
$r3$.ɵɵelement(0, "lifecycle-comp", 0)(1, "lifecycle-comp", 0);
|
||||
}
|
||||
if (rf & 2) {
|
||||
$r3$.ɵɵproperty("name", ctx.name1);
|
||||
|
||||
+1
-2
@@ -10,8 +10,7 @@ MyApp.ɵcmp = /*@__PURE__*/ $r3$.ɵɵdefineComponent({
|
||||
consts: [[__AttributeMarker.Bindings__, "dir"]],
|
||||
template: function MyApp_Template(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵɵelement(0, "div", 0);
|
||||
$r3$.ɵɵelement(1, "div", 0);
|
||||
$r3$.ɵɵelement(0, "div", 0)(1, "div", 0);
|
||||
}
|
||||
if (rf & 2) {
|
||||
$r3$.ɵɵproperty("dir", $r3$.ɵɵpureFunction0(2, $c0$));
|
||||
|
||||
+1
-2
@@ -9,8 +9,7 @@ MyApp.ɵcmp = /*@__PURE__*/ $r3$.ɵɵdefineComponent({
|
||||
consts: [[__AttributeMarker.Bindings__, "dir"]],
|
||||
template: function MyApp_Template(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵɵelement(0, "div", 0);
|
||||
$r3$.ɵɵelement(1, "div", 0);
|
||||
$r3$.ɵɵelement(0, "div", 0)(1, "div", 0);
|
||||
}
|
||||
if (rf & 2) {
|
||||
$r3$.ɵɵproperty("dir", $r3$.ɵɵpureFunction0(2, $c0$));
|
||||
|
||||
+2
-4
@@ -14,14 +14,12 @@ function MyComponent_li_1_li_4_Template(rf, ctx) {
|
||||
|
||||
function MyComponent_li_1_Template(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵɵelementStart(0, "li");
|
||||
$r3$.ɵɵelementStart(1, "div");
|
||||
$r3$.ɵɵelementStart(0, "li")(1, "div");
|
||||
$r3$.ɵɵtext(2);
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementStart(3, "ul");
|
||||
$r3$.ɵɵtemplate(4, MyComponent_li_1_li_4_Template, 2, 2, "li", 0);
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd()();
|
||||
}
|
||||
if (rf & 2) {
|
||||
const $item$ = ctx.$implicit;
|
||||
|
||||
+1
-2
@@ -1,8 +1,7 @@
|
||||
consts: [["title", "hi"]],
|
||||
template: function MyComponent_Template(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵɵelement(0, "div", 0);
|
||||
$r3$.ɵɵelement(1, "span", 0);
|
||||
$r3$.ɵɵelement(0, "div", 0)(1, "span", 0);
|
||||
}
|
||||
…
|
||||
}
|
||||
+1
-2
@@ -10,7 +10,6 @@ template: function MyComponent_Template(rf, ctx) {
|
||||
$r3$.ɵɵnamespaceHTML();
|
||||
$r3$.ɵɵelementStart(3, "p");
|
||||
$r3$.ɵɵtext(4, "test");
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd()();
|
||||
}
|
||||
}
|
||||
+1
-5
@@ -6,11 +6,7 @@ consts: [
|
||||
],
|
||||
template: function MyComponent_Template(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵɵelement(0, "embed", 0);
|
||||
$r3$.ɵɵelement(1, "iframe", 1);
|
||||
$r3$.ɵɵelement(2, "object", 2);
|
||||
$r3$.ɵɵelement(3, "embed", 0);
|
||||
$r3$.ɵɵelement(4, "img", 3);
|
||||
$r3$.ɵɵelement(0, "embed", 0)(1, "iframe", 1)(2, "object", 2)(3, "embed", 0)(4, "img", 3);
|
||||
}
|
||||
…
|
||||
}
|
||||
|
||||
+1
-2
@@ -9,7 +9,6 @@ consts: [["title", "Hello", 1, "my-app"], ["cx", "20", "cy", "30", "r", "50"]],
|
||||
$r3$.ɵɵnamespaceHTML();
|
||||
$r3$.ɵɵelementStart(3, "p");
|
||||
$r3$.ɵɵtext(4, "test");
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd()();
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -1,7 +1,6 @@
|
||||
template: function MyApp_Template(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
i0.ɵɵelement(0, "div", 0);
|
||||
i0.ɵɵelement(1, "span", 0);
|
||||
i0.ɵɵelement(0, "div", 0)(1, "span", 0);
|
||||
}
|
||||
if (rf & 2) {
|
||||
let $tmp_0_0$;
|
||||
|
||||
+2
-4
@@ -1,11 +1,9 @@
|
||||
function MyComponent_div_0_Template(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵɵelementStart(0, "div");
|
||||
$r3$.ɵɵelementStart(1, "div", 1);
|
||||
$r3$.ɵɵelementStart(0, "div")(1, "div", 1);
|
||||
$r3$.ɵɵpipe(2, "uppercase");
|
||||
$r3$.ɵɵi18nAttributes(3, 2);
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd()();
|
||||
}
|
||||
if (rf & 2) {
|
||||
const $outer_r1$ = ctx.$implicit;
|
||||
|
||||
+2
-4
@@ -25,15 +25,13 @@ consts: function() {
|
||||
template: function MyComponent_Template(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵɵnamespaceSVG();
|
||||
$r3$.ɵɵelementStart(0, "svg", 0);
|
||||
$r3$.ɵɵelementStart(1, "foreignObject");
|
||||
$r3$.ɵɵelementStart(0, "svg", 0)(1, "foreignObject");
|
||||
$r3$.ɵɵi18nStart(2, 1);
|
||||
$r3$.ɵɵnamespaceHTML();
|
||||
$r3$.ɵɵelementStart(3, "div", 2);
|
||||
$r3$.ɵɵelement(4, "span");
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵi18nEnd();
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd()();
|
||||
}
|
||||
}
|
||||
|
||||
+2
-5
@@ -22,15 +22,12 @@ consts: function() {
|
||||
template: function MyComponent_Template(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵɵnamespaceSVG();
|
||||
$r3$.ɵɵelementStart(0, "svg", 0);
|
||||
$r3$.ɵɵelementStart(1, "foreignObject");
|
||||
$r3$.ɵɵelementStart(0, "svg", 0)(1, "foreignObject");
|
||||
$r3$.ɵɵnamespaceHTML();
|
||||
$r3$.ɵɵelementStart(2, "div", 1);
|
||||
$r3$.ɵɵi18nStart(3, 2);
|
||||
$r3$.ɵɵelement(4, "span");
|
||||
$r3$.ɵɵi18nEnd();
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd()()();
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -1,7 +1,5 @@
|
||||
template: function MyComponent_Template(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵɵelement(0, "div");
|
||||
$r3$.ɵɵelement(1, "div");
|
||||
$r3$.ɵɵelement(2, "div");
|
||||
$r3$.ɵɵelement(0, "div")(1, "div")(2, "div");
|
||||
}
|
||||
}
|
||||
+2
-4
@@ -18,11 +18,9 @@ template: function MyComponent_Template(rf, ctx) {
|
||||
$r3$.ɵɵelementStart(3, "div");
|
||||
$r3$.ɵɵi18nStart(4, 1);
|
||||
$r3$.ɵɵpipe(5, "uppercase");
|
||||
$r3$.ɵɵelementStart(6, "div");
|
||||
$r3$.ɵɵelementStart(7, "div");
|
||||
$r3$.ɵɵelementStart(6, "div")(7, "div");
|
||||
$r3$.ɵɵelement(8, "span");
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd()();
|
||||
$r3$.ɵɵi18nEnd();
|
||||
$r3$.ɵɵelementEnd();
|
||||
}
|
||||
|
||||
+2
-4
@@ -1,13 +1,11 @@
|
||||
function MyComponent_div_2_Template(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵɵelementStart(0, "div");
|
||||
$r3$.ɵɵelementStart(1, "div");
|
||||
$r3$.ɵɵelementStart(0, "div")(1, "div");
|
||||
$r3$.ɵɵi18nStart(2, 1);
|
||||
$r3$.ɵɵelement(3, "div");
|
||||
$r3$.ɵɵpipe(4, "uppercase");
|
||||
$r3$.ɵɵi18nEnd();
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd()();
|
||||
}
|
||||
if (rf & 2) {
|
||||
const $ctx_r0$ = $r3$.ɵɵnextContext();
|
||||
|
||||
+2
-4
@@ -16,12 +16,10 @@ function MyComponent_div_2_div_4_Template(rf, ctx) {
|
||||
function MyComponent_div_2_Template(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵɵi18nStart(0, 0, 1);
|
||||
$r3$.ɵɵelementStart(1, "div");
|
||||
$r3$.ɵɵelementStart(2, "div");
|
||||
$r3$.ɵɵelementStart(1, "div")(2, "div");
|
||||
$r3$.ɵɵpipe(3, "uppercase");
|
||||
$r3$.ɵɵtemplate(4, MyComponent_div_2_div_4_Template, 3, 2, "div", 1);
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd()();
|
||||
$r3$.ɵɵi18nEnd();
|
||||
}
|
||||
if (rf & 2) {
|
||||
|
||||
+2
-4
@@ -1,8 +1,7 @@
|
||||
function MyComponent_div_0_Template(rf, ctx) {
|
||||
if (rf & 1) {
|
||||
const $s$ = $r3$.ɵɵgetCurrentView();
|
||||
$r3$.ɵɵelementStart(0, "div");
|
||||
$r3$.ɵɵelementStart(1, "div", 1);
|
||||
$r3$.ɵɵelementStart(0, "div")(1, "div", 1);
|
||||
$r3$.ɵɵlistener("click", function MyComponent_div_0_Template_div_click_1_listener() {
|
||||
$r3$.ɵɵrestoreView($s$);
|
||||
const $comp$ = $r3$.ɵɵnextContext();
|
||||
@@ -15,8 +14,7 @@ function MyComponent_div_0_Template(rf, ctx) {
|
||||
const $comp2$ = $r3$.ɵɵnextContext();
|
||||
return $comp2$.onClick2($comp2$.bar);
|
||||
});
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd();
|
||||
$r3$.ɵɵelementEnd()();
|
||||
}
|
||||
}
|
||||
// ...
|
||||
|
||||
+1
-3
@@ -5,9 +5,7 @@ MyComponent.ɵcmp = /*@__PURE__*/ $r3$.ɵɵdefineComponent({
|
||||
vars: 3,
|
||||
template: function MyComponent_Template(rf, $ctx$) {
|
||||
if (rf & 1) {
|
||||
$r3$.ɵɵelement(0, "div");
|
||||
$r3$.ɵɵelement(1, "div");
|
||||
$r3$.ɵɵelement(2, "div");
|
||||
$r3$.ɵɵelement(0, "div")(1, "div")(2, "div");
|
||||
}
|
||||
if (rf & 2) {
|
||||
$r3$.ɵɵproperty("@foo", ctx.exp);
|
||||
|
||||
@@ -52,6 +52,12 @@ export const RESTORED_VIEW_CONTEXT_NAME = 'restoredCtx';
|
||||
|
||||
/** Instructions that support chaining. */
|
||||
const CHAINABLE_INSTRUCTIONS = new Set([
|
||||
R3.element,
|
||||
R3.elementStart,
|
||||
R3.elementEnd,
|
||||
R3.elementContainer,
|
||||
R3.elementContainerStart,
|
||||
R3.elementContainerEnd,
|
||||
R3.i18nExp,
|
||||
R3.listener,
|
||||
R3.classProp,
|
||||
|
||||
@@ -63,6 +63,7 @@ function elementStartFirstCreatePass(
|
||||
* @param name Name of the DOM Node
|
||||
* @param attrsIndex Index of the element's attributes in the `consts` array.
|
||||
* @param localRefsIndex Index of the element's local references in the `consts` array.
|
||||
* @returns This function returns itself so that it may be chained.
|
||||
*
|
||||
* Attributes and localRefs are passed as an array of strings where elements with an even index
|
||||
* hold an attribute name and elements with an odd index hold an attribute value, ex.:
|
||||
@@ -71,7 +72,8 @@ function elementStartFirstCreatePass(
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵelementStart(
|
||||
index: number, name: string, attrsIndex?: number|null, localRefsIndex?: number): void {
|
||||
index: number, name: string, attrsIndex?: number|null,
|
||||
localRefsIndex?: number): typeof ɵɵelementStart {
|
||||
const lView = getLView();
|
||||
const tView = getTView();
|
||||
const adjustedIndex = HEADER_OFFSET + index;
|
||||
@@ -125,14 +127,16 @@ export function ɵɵelementStart(
|
||||
if (localRefsIndex !== null) {
|
||||
saveResolvedLocalsInData(lView, tNode);
|
||||
}
|
||||
return ɵɵelementStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the end of the element.
|
||||
* @returns This function returns itself so that it may be chained.
|
||||
*
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵelementEnd(): void {
|
||||
export function ɵɵelementEnd(): typeof ɵɵelementEnd {
|
||||
let currentTNode = getCurrentTNode()!;
|
||||
ngDevMode && assertDefined(currentTNode, 'No parent node to close.');
|
||||
if (isCurrentTNodeParent()) {
|
||||
@@ -164,6 +168,7 @@ export function ɵɵelementEnd(): void {
|
||||
if (tNode.stylesWithoutHost != null && hasStyleInput(tNode)) {
|
||||
setDirectiveInputsWhichShadowsStyling(tView, tNode, getLView(), tNode.stylesWithoutHost, false);
|
||||
}
|
||||
return ɵɵelementEnd;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,13 +178,16 @@ export function ɵɵelementEnd(): void {
|
||||
* @param name Name of the DOM Node
|
||||
* @param attrsIndex Index of the element's attributes in the `consts` array.
|
||||
* @param localRefsIndex Index of the element's local references in the `consts` array.
|
||||
* @returns This function returns itself so that it may be chained.
|
||||
*
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵelement(
|
||||
index: number, name: string, attrsIndex?: number|null, localRefsIndex?: number): void {
|
||||
index: number, name: string, attrsIndex?: number|null,
|
||||
localRefsIndex?: number): typeof ɵɵelement {
|
||||
ɵɵelementStart(index, name, attrsIndex, localRefsIndex);
|
||||
ɵɵelementEnd();
|
||||
return ɵɵelement;
|
||||
}
|
||||
|
||||
function logUnknownElementError(
|
||||
|
||||
@@ -11,7 +11,7 @@ import {attachPatchData} from '../context_discovery';
|
||||
import {registerPostOrderHooks} from '../hooks';
|
||||
import {TAttributes, TElementContainerNode, TNodeType} from '../interfaces/node';
|
||||
import {isContentQueryHost, isDirectiveHost} from '../interfaces/type_checks';
|
||||
import {HEADER_OFFSET, LView, RENDERER, T_HOST, TView} from '../interfaces/view';
|
||||
import {HEADER_OFFSET, LView, RENDERER, TView} from '../interfaces/view';
|
||||
import {assertTNodeType} from '../node_assert';
|
||||
import {appendChild} from '../node_manipulation';
|
||||
import {getBindingIndex, getCurrentTNode, getLView, getTView, isCurrentTNodeParent, setCurrentTNode, setCurrentTNodeAsNotParent} from '../state';
|
||||
@@ -52,6 +52,7 @@ function elementContainerStartFirstCreatePass(
|
||||
* @param index Index of the element in the LView array
|
||||
* @param attrsIndex Index of the container attributes in the `consts` array.
|
||||
* @param localRefsIndex Index of the container's local references in the `consts` array.
|
||||
* @returns This function returns itself so that it may be chained.
|
||||
*
|
||||
* Even if this instruction accepts a set of attributes no actual attribute values are propagated to
|
||||
* the DOM (as a comment node can't have attributes). Attributes are here only for directive
|
||||
@@ -60,7 +61,8 @@ function elementContainerStartFirstCreatePass(
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵelementContainerStart(
|
||||
index: number, attrsIndex?: number|null, localRefsIndex?: number): void {
|
||||
index: number, attrsIndex?: number|null,
|
||||
localRefsIndex?: number): typeof ɵɵelementContainerStart {
|
||||
const lView = getLView();
|
||||
const tView = getTView();
|
||||
const adjustedIndex = index + HEADER_OFFSET;
|
||||
@@ -91,14 +93,17 @@ export function ɵɵelementContainerStart(
|
||||
if (localRefsIndex != null) {
|
||||
saveResolvedLocalsInData(lView, tNode);
|
||||
}
|
||||
|
||||
return ɵɵelementContainerStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the end of the <ng-container>.
|
||||
* @returns This function returns itself so that it may be chained.
|
||||
*
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵelementContainerEnd(): void {
|
||||
export function ɵɵelementContainerEnd(): typeof ɵɵelementContainerEnd {
|
||||
let currentTNode = getCurrentTNode()!;
|
||||
const tView = getTView();
|
||||
if (isCurrentTNodeParent()) {
|
||||
@@ -117,6 +122,7 @@ export function ɵɵelementContainerEnd(): void {
|
||||
tView.queries!.elementEnd(currentTNode);
|
||||
}
|
||||
}
|
||||
return ɵɵelementContainerEnd;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,11 +132,13 @@ export function ɵɵelementContainerEnd(): void {
|
||||
* @param index Index of the element in the LView array
|
||||
* @param attrsIndex Index of the container attributes in the `consts` array.
|
||||
* @param localRefsIndex Index of the container's local references in the `consts` array.
|
||||
* @returns This function returns itself so that it may be chained.
|
||||
*
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵelementContainer(
|
||||
index: number, attrsIndex?: number|null, localRefsIndex?: number): void {
|
||||
index: number, attrsIndex?: number|null, localRefsIndex?: number): typeof ɵɵelementContainer {
|
||||
ɵɵelementContainerStart(index, attrsIndex, localRefsIndex);
|
||||
ɵɵelementContainerEnd();
|
||||
return ɵɵelementContainer;
|
||||
}
|
||||
|
||||
@@ -1475,6 +1475,9 @@
|
||||
{
|
||||
"name": "ɵɵelement"
|
||||
},
|
||||
{
|
||||
"name": "ɵɵelementEnd"
|
||||
},
|
||||
{
|
||||
"name": "ɵɵelementStart"
|
||||
},
|
||||
|
||||
@@ -362,6 +362,12 @@
|
||||
{
|
||||
"name": "ɵɵdefineComponent"
|
||||
},
|
||||
{
|
||||
"name": "ɵɵelement"
|
||||
},
|
||||
{
|
||||
"name": "ɵɵelementEnd"
|
||||
},
|
||||
{
|
||||
"name": "ɵɵelementStart"
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ describe('jit source mapping', () => {
|
||||
}));
|
||||
|
||||
it('should report di errors with multiple elements and directives', fakeAsync(() => {
|
||||
const template = `<div someDir></div><div someDir="throw"></div>`;
|
||||
const template = `<div someDir></div>|<div someDir="throw"></div>`;
|
||||
|
||||
@Component({...templateDecorator(template)})
|
||||
class MyComp {
|
||||
@@ -146,7 +146,7 @@ describe('jit source mapping', () => {
|
||||
// The error should be logged from the 2nd-element
|
||||
expect(jitEvaluator.getSourcePositionForStack(error.stack, generatedUrl)).toEqual({
|
||||
line: 1,
|
||||
column: 19,
|
||||
column: 20,
|
||||
source: ngUrl,
|
||||
});
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user