diff --git a/projects/ng-devtools-backend/src/lib/hooks/capture.ts b/projects/ng-devtools-backend/src/lib/hooks/capture.ts index 28c855a7316..e698b1f8e6e 100644 --- a/projects/ng-devtools-backend/src/lib/hooks/capture.ts +++ b/projects/ng-devtools-backend/src/lib/hooks/capture.ts @@ -31,20 +31,20 @@ export const stop = (): ProfilerFrame => { return result; }; -const startEvent = (map: { [key: string]: number }, directive: any, label: string) => { +const startEvent = (map: Record, directive: any, label: string) => { const name = getDirectiveName(directive); const key = `${name}#${label}`; map[key] = performance.now(); }; -const getEventStart = (map: { [key: string]: number }, directive: any, label: string) => { +const getEventStart = (map: Record, directive: any, label: string) => { const name = getDirectiveName(directive); const key = `${name}#${label}`; return map[key]; }; const getHooks = (onFrame: (frame: ProfilerFrame) => void): Partial => { - const timeStartMap: { [key: string]: number } = {}; + const timeStartMap: Record = {}; return { // We flush here because it's possible the current node to overwrite // an existing removed node. @@ -82,6 +82,7 @@ const getHooks = (onFrame: (frame: ProfilerFrame) => void): Partial => { }, onChangeDetectionEnd(component: any): void { const profile = eventMap.get(component); + if (profile) { let current = profile.changeDetection; if (current === undefined) { diff --git a/projects/ng-devtools-backend/src/lib/hooks/profiler/native.ts b/projects/ng-devtools-backend/src/lib/hooks/profiler/native.ts index a4c84c126c8..d86a0fcc8f1 100644 --- a/projects/ng-devtools-backend/src/lib/hooks/profiler/native.ts +++ b/projects/ng-devtools-backend/src/lib/hooks/profiler/native.ts @@ -10,6 +10,7 @@ type ProfilerCallback = (event: ɵProfilerEvent, instanceOrLView: {}, hookOrList export class NgProfiler extends Profiler { private _tracker = IdentityTracker.getInstance(); private _callbacks: ProfilerCallback[] = []; + private _lastDirectiveInstance: {} | null = null; constructor(config: Partial = {}) { super(config); @@ -66,7 +67,7 @@ export class NgProfiler extends Profiler { return; } - [ɵProfilerEvent.TemplateUpdateStart](directive: any, _hookOrListener: any): void { + [ɵProfilerEvent.TemplateUpdateStart](context: any, _hookOrListener: any): void { if (!this._inChangeDetection) { this._inChangeDetection = true; runOutsideAngular(() => { @@ -77,19 +78,44 @@ export class NgProfiler extends Profiler { }); } - const position = this._tracker.getDirectivePosition(directive); - const id = this._tracker.getDirectiveId(directive); + const position = this._tracker.getDirectivePosition(context); + const id = this._tracker.getDirectiveId(context); - this._onChangeDetectionStart(directive, getDirectiveHostElement(directive), id, position); + // If we can find the position and the ID we assume that this is a component instance. + // Alternatively, if we can't find the ID or the position, we assume that this is a + // context of an embedded view (for example, NgForOfContext, NgIfContext, or a custom one). + if (position !== undefined && id !== undefined) { + this._lastDirectiveInstance = context; + } + + if (id !== undefined && position !== undefined) { + this._onChangeDetectionStart(context, getDirectiveHostElement(context), id, position); + return; + } + + this._onChangeDetectionStart( + this._lastDirectiveInstance, + getDirectiveHostElement(this._lastDirectiveInstance), + this._tracker.getDirectiveId(this._lastDirectiveInstance), + this._tracker.getDirectivePosition(this._lastDirectiveInstance) + ); } - [ɵProfilerEvent.TemplateUpdateEnd](directive: any, _hookOrListener: any): void { - const position = this._tracker.getDirectivePosition(directive); - const id = this._tracker.getDirectiveId(directive); + [ɵProfilerEvent.TemplateUpdateEnd](context: any, _hookOrListener: any): void { + const position = this._tracker.getDirectivePosition(context); + const id = this._tracker.getDirectiveId(context); - if (this._tracker.hasDirective(directive) && id !== undefined && position !== undefined) { - this._onChangeDetectionEnd(directive, getDirectiveHostElement(directive), id, position); + if (this._tracker.hasDirective(context) && id !== undefined && position !== undefined) { + this._onChangeDetectionEnd(context, getDirectiveHostElement(context), id, position); + return; } + + this._onChangeDetectionEnd( + this._lastDirectiveInstance, + getDirectiveHostElement(this._lastDirectiveInstance), + this._tracker.getDirectiveId(this._lastDirectiveInstance), + this._tracker.getDirectivePosition(this._lastDirectiveInstance) + ); } [ɵProfilerEvent.LifecycleHookStart](directive: any, hook: any): void {