mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(devtools): support defer blocks in IdentityTracker (#61139)
This reverts the fix of #61080 which wasn't adequate. PR Close #61139
This commit is contained in:
committed by
Andrew Kushnir
parent
70f959b3bd
commit
6cd5d8ebdc
@@ -267,6 +267,7 @@ const insertElementProfile = (
|
||||
let lastFrame: ElementProfile = {
|
||||
children: [],
|
||||
directives: [],
|
||||
type: 'element',
|
||||
};
|
||||
if (frames[lastIdx]) {
|
||||
lastFrame = frames[lastIdx];
|
||||
@@ -290,6 +291,8 @@ const prepareInitialFrame = (source: string, duration: number) => {
|
||||
position = directiveForestHooks.getDirectivePosition(node.component.instance);
|
||||
} else if (node.directives[0]) {
|
||||
position = directiveForestHooks.getDirectivePosition(node.directives[0].instance);
|
||||
} else if (node.defer) {
|
||||
position = directiveForestHooks.getDirectivePosition(node.defer);
|
||||
}
|
||||
|
||||
if (position === undefined) {
|
||||
@@ -313,9 +316,10 @@ const prepareInitialFrame = (source: string, duration: number) => {
|
||||
name: getDirectiveName(node.component.instance),
|
||||
});
|
||||
}
|
||||
const result = {
|
||||
const result: ElementProfile = {
|
||||
children: [],
|
||||
directives,
|
||||
type: node.defer ? 'defer' : 'element',
|
||||
};
|
||||
children[position[position.length - 1]] = result;
|
||||
node.children.forEach((n) => traverse(n, result.children));
|
||||
|
||||
@@ -96,6 +96,9 @@ export class IdentityTracker {
|
||||
this.isComponent.set(dir.instance, false);
|
||||
this._indexNode(dir.instance, node.position, newNodes);
|
||||
});
|
||||
if (node.defer) {
|
||||
this._indexNode(node.defer, node.position, newNodes);
|
||||
}
|
||||
node.children.forEach((child) => this._index(child, parent, newNodes, allNodes));
|
||||
}
|
||||
|
||||
@@ -124,21 +127,12 @@ const indexTree = <T extends DevToolsNode<DirectiveInstanceType, ComponentInstan
|
||||
parentPosition: number[] = [],
|
||||
): IndexedNode => {
|
||||
const position = parentPosition.concat([idx]);
|
||||
|
||||
// Not every node represents a DOM element (ex @defer blocks), we shouldn't account for them
|
||||
const children: IndexedNode[] = [];
|
||||
node.children.forEach((n, i) => {
|
||||
if (n.nativeElement) {
|
||||
children.push(indexTree(n, i, position));
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
position,
|
||||
element: node.element,
|
||||
component: node.component,
|
||||
directives: node.directives.map((d) => ({position, ...d})),
|
||||
children,
|
||||
children: node.children.map((n, i) => indexTree(n, i, position)),
|
||||
nativeElement: node.nativeElement,
|
||||
hydration: node.hydration,
|
||||
defer: node.defer,
|
||||
@@ -147,5 +141,4 @@ const indexTree = <T extends DevToolsNode<DirectiveInstanceType, ComponentInstan
|
||||
|
||||
export const indexForest = <T extends DevToolsNode<DirectiveInstanceType, ComponentInstanceType>>(
|
||||
forest: T[],
|
||||
// Not every node represents a DOM element (ex @defer blocks), we shouldn't account for them
|
||||
): IndexedNode[] => forest.filter((n) => n.nativeElement).map((n, i) => indexTree(n, i));
|
||||
): IndexedNode[] => forest.map((n, i) => indexTree(n, i));
|
||||
|
||||
+1
@@ -38,6 +38,7 @@ export class FlamegraphFormatter extends RecordFormatter<FlamegraphNode> {
|
||||
original: {
|
||||
children: [],
|
||||
directives: [],
|
||||
type: 'element',
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
+12
-4
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {ProfilerFrame} from 'protocol';
|
||||
import {ElementProfile, ProfilerFrame} from 'protocol';
|
||||
|
||||
import {mergeFrames} from './frame-merger';
|
||||
|
||||
@@ -16,7 +16,7 @@ describe('mergeFrames', () => {
|
||||
});
|
||||
|
||||
it('should work with a single frame', () => {
|
||||
const frame = {
|
||||
const frame: ProfilerFrame = {
|
||||
directives: [
|
||||
{
|
||||
children: [],
|
||||
@@ -29,6 +29,7 @@ describe('mergeFrames', () => {
|
||||
name: 'Foo',
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
},
|
||||
],
|
||||
duration: 5,
|
||||
@@ -43,7 +44,7 @@ describe('mergeFrames', () => {
|
||||
});
|
||||
|
||||
it('should merge frames when nesting matches', () => {
|
||||
const frame = {
|
||||
const frame: ProfilerFrame = {
|
||||
directives: [
|
||||
{
|
||||
children: [],
|
||||
@@ -57,6 +58,7 @@ describe('mergeFrames', () => {
|
||||
name: 'Foo',
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
},
|
||||
],
|
||||
duration: 5,
|
||||
@@ -78,6 +80,7 @@ describe('mergeFrames', () => {
|
||||
name: 'Foo',
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
},
|
||||
],
|
||||
duration: 10,
|
||||
@@ -86,7 +89,7 @@ describe('mergeFrames', () => {
|
||||
});
|
||||
|
||||
it('should merge frames when nesting does not match', () => {
|
||||
const frame = {
|
||||
const frame: ProfilerFrame = {
|
||||
directives: [
|
||||
{
|
||||
children: [],
|
||||
@@ -100,6 +103,7 @@ describe('mergeFrames', () => {
|
||||
name: 'Foo',
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
},
|
||||
],
|
||||
duration: 5,
|
||||
@@ -122,6 +126,7 @@ describe('mergeFrames', () => {
|
||||
name: 'Foo',
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
},
|
||||
],
|
||||
directives: [
|
||||
@@ -134,6 +139,7 @@ describe('mergeFrames', () => {
|
||||
name: 'Foo',
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
},
|
||||
],
|
||||
duration: 5,
|
||||
@@ -157,6 +163,7 @@ describe('mergeFrames', () => {
|
||||
name: 'Foo',
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
},
|
||||
],
|
||||
directives: [
|
||||
@@ -169,6 +176,7 @@ describe('mergeFrames', () => {
|
||||
name: 'Foo',
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
},
|
||||
],
|
||||
duration: 10,
|
||||
|
||||
+1
@@ -32,6 +32,7 @@ const mergeDirectives = (mergeIn: ElementProfile[], second: ElementProfile[]) =>
|
||||
mergeIn[i] = {
|
||||
children: [],
|
||||
directives: [],
|
||||
type: 'element',
|
||||
};
|
||||
}
|
||||
second[i].directives.forEach((d, idx) => {
|
||||
|
||||
+18
-1
@@ -6,6 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {ElementProfile} from 'protocol';
|
||||
import {FlamegraphNode} from './flamegraph-formatter';
|
||||
|
||||
export const SIMPLE_RECORD = [
|
||||
@@ -33,6 +34,7 @@ export const SIMPLE_RECORD = [
|
||||
changeDetected: true,
|
||||
},
|
||||
],
|
||||
type: 'element' as ElementProfile['type'],
|
||||
},
|
||||
],
|
||||
directives: [
|
||||
@@ -46,6 +48,7 @@ export const SIMPLE_RECORD = [
|
||||
changeDetection: 0,
|
||||
},
|
||||
],
|
||||
type: 'element' as ElementProfile['type'],
|
||||
},
|
||||
];
|
||||
export const SIMPLE_FORMATTED_FLAMEGRAPH_RECORD = [
|
||||
@@ -84,7 +87,7 @@ export const SIMPLE_FORMATTED_TREE_MAP_RECORD = [
|
||||
original: SIMPLE_RECORD[0],
|
||||
}),
|
||||
];
|
||||
export const NESTED_RECORD = [
|
||||
export const NESTED_RECORD: ElementProfile[] = [
|
||||
{
|
||||
children: [
|
||||
{
|
||||
@@ -121,6 +124,7 @@ export const NESTED_RECORD = [
|
||||
name: 'TodoComponent',
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
@@ -142,6 +146,7 @@ export const NESTED_RECORD = [
|
||||
name: 'TodoComponent',
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
@@ -163,6 +168,7 @@ export const NESTED_RECORD = [
|
||||
name: 'TodoComponent',
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
},
|
||||
],
|
||||
directives: [
|
||||
@@ -175,6 +181,7 @@ export const NESTED_RECORD = [
|
||||
changeDetection: 0,
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
},
|
||||
],
|
||||
directives: [
|
||||
@@ -187,6 +194,7 @@ export const NESTED_RECORD = [
|
||||
name: 'TodosComponent',
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
},
|
||||
],
|
||||
directives: [
|
||||
@@ -199,6 +207,7 @@ export const NESTED_RECORD = [
|
||||
changeDetection: 0,
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
},
|
||||
],
|
||||
directives: [
|
||||
@@ -211,6 +220,7 @@ export const NESTED_RECORD = [
|
||||
name: 'AppComponent',
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
},
|
||||
],
|
||||
directives: [
|
||||
@@ -223,6 +233,7 @@ export const NESTED_RECORD = [
|
||||
changeDetection: 0,
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
@@ -236,6 +247,7 @@ export const NESTED_RECORD = [
|
||||
name: 'HeavyComponent',
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
},
|
||||
],
|
||||
directives: [
|
||||
@@ -248,6 +260,7 @@ export const NESTED_RECORD = [
|
||||
name: 'DemoAppComponent',
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
},
|
||||
],
|
||||
directives: [
|
||||
@@ -260,6 +273,7 @@ export const NESTED_RECORD = [
|
||||
changeDetection: 0,
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
},
|
||||
],
|
||||
directives: [
|
||||
@@ -272,6 +286,7 @@ export const NESTED_RECORD = [
|
||||
name: 'AppComponent',
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
},
|
||||
{
|
||||
children: [],
|
||||
@@ -285,6 +300,7 @@ export const NESTED_RECORD = [
|
||||
name: 'ZippyComponent',
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
},
|
||||
];
|
||||
export const NESTED_FORMATTED_FLAMEGRAPH_RECORD: FlamegraphNode[] = [
|
||||
@@ -425,6 +441,7 @@ export const NESTED_FORMATTED_FLAMEGRAPH_RECORD: FlamegraphNode[] = [
|
||||
name: 'ZippyComponent',
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
+4
@@ -106,6 +106,7 @@ describe('getLabel cases', () => {
|
||||
name: 'AppComponent',
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
};
|
||||
expect(formatter.getLabel(element)).toBe('AppComponent');
|
||||
});
|
||||
@@ -123,6 +124,7 @@ describe('getLabel cases', () => {
|
||||
changeDetection: 0,
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
};
|
||||
expect(formatter.getLabel(element)).toBe('[RouterOutlet]');
|
||||
});
|
||||
@@ -148,6 +150,7 @@ describe('getLabel cases', () => {
|
||||
name: 'TodoComponent',
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
};
|
||||
expect(formatter.getLabel(element)).toBe('TodoComponent[TooltipDirective]');
|
||||
});
|
||||
@@ -181,6 +184,7 @@ describe('getLabel cases', () => {
|
||||
name: 'TodoComponent',
|
||||
},
|
||||
],
|
||||
type: 'element',
|
||||
};
|
||||
expect(formatter.getLabel(element)).toBe('TodoComponent[TooltipDirective, RandomDirective]');
|
||||
});
|
||||
|
||||
+4
@@ -29,6 +29,10 @@ export abstract class RecordFormatter<T> {
|
||||
abstract addFrame(nodes: T | T[], elements: ElementProfile[]): number | void;
|
||||
|
||||
getLabel(element: ElementProfile): string {
|
||||
if (element.type === 'defer') {
|
||||
return '@defer';
|
||||
}
|
||||
|
||||
const name = element.directives
|
||||
.filter((d) => d.isComponent)
|
||||
.map((c) => c.name)
|
||||
|
||||
@@ -250,6 +250,7 @@ export interface DirectiveProfile {
|
||||
export interface ElementProfile {
|
||||
directives: DirectiveProfile[];
|
||||
children: ElementProfile[];
|
||||
type: 'defer' | 'element';
|
||||
}
|
||||
|
||||
export interface ProfilerFrame {
|
||||
|
||||
Reference in New Issue
Block a user