Prevent Angular DevTools from crashing when elements matching [ng-version] in the DOM do not belong to the host application (such as third-party custom elements or browser extensions). ng.getComponent returns null for these elements, which previously caused ng.getDirectiveMetadata to throw.
(cherry picked from commit ef09d108f2)
Use a custom logger that prefixes the messages with `[Angular DevTools]`;
Add ability for dev-only log messages;
Add Angular-DevTools-specific `Error`;
(cherry picked from commit 1371c946aa)
We keep getting PRs that target single usages of `hasOwnProperty` and we have ~100 of them. These changes aim to address the issue centrally by swapping out all the instances and adding a lint rule against introducing new ones.
(cherry picked from commit 732e505018)
This fixes a regression introduced by #69309 where the format of `serializedId` from a coma separated string, to a JSON representation of an array.
fixes#70104
(cherry picked from commit 03f1758e2a)
Move the DebugSignalGraph, DebugSignalGraphEdge, and DebugSignalGraphNode interfaces from packages/core/src/render3/util/signal_debug.ts into the packages/core/primitives/devtools/src package. This decouples the signal graph debug types from runtime render3 utilities and allows devtools and internal core tooling to import them directly from primitives as type-only exports.
Before SVG hosts could be skipped because the highlighter checked for HTMLElement. A case like <foreignObject appSvgDemo> would not get a proper overlay. The highlighter now works with Element so SVG hosts can be found and measured.
Before Directive only hosts could be skipped because the inspected-page lookup and directive explorer matched component hosts and component ids only. A case like <a routerLink="/todos">Todos</a> could highlight the parent component instead of the anchor, and the RouterLink only tree node could fail to select, highlight, or request an overlay. Id 0 could also miss the highlighted state because the tree treated it as absent. The lookup now stops at the nearest component or directive host, and tree matching accepts component and directive ids using null as the absent state.
Selected overlays could fail to reappear for the same element because unhighlighting removed the overlay but left the selected element cached. selected-element cache is now reused only while its overlay is still connected, and unhighlighting clears the cached element.
Overlay geometry used integer coercion. An SVG or transformed element with a 0.5px bounding box could get a 0px overlay. Overlay positioning now preserves fractional DOMRect values.
Enables direct navigation to Angular components from the Chrome Performance panel's flame graph.
This feature integrates Angular DevTools with Chrome's `setOpenResourceHandler` by registering a custom URL scheme (`angular-devtools://component/{instanceId}`).
Closes#63960
- Rename `DirectiveForestHooks` to `DirectiveForestManager`
- Keep profiler reference standalone; move it out from `DirectiveForestHooks`/`DirectiveForestManager`
- Convert profiler-specific `IdentityTracker` behavior to a more generalized one
- Separate timing API functionality from the `DirectiveForestHooks`/`DirectiveForestManager` initialization fn
- Reorganize files; rename `/hooks` to `/profiling`
- Use concrete types for directive and component instances (incomplete coverage; based on `any` at the moment)
- Other more minor changes
This refactoring renames the 'element' (tagName string) property of DevToolsNode to 'tagName' for clarity, as 'element' was ambiguous.
It also restores 'nativeElement' as a flat property (undoing the nesting introduced previously) because there are cases (like control flow blocks) where a tag name is present without an associated DOM node, making nesting inappropriate.
- promote to default-on (remove opt-in setting and gear-menu toggle)
- replace the <pre> value cell with a collapsible JSON tree
- add key filter and column sort (size sorts by raw bytes)
- show an educational empty state when the app has no transfer state
- iterate every root in the directive forest and merge their state
- guard size calculation against undefined and circular references
- register listener once with DestroyRef cleanup; add a loading timeout
- distinguish array/string badge colors via theme-aware tokens
- responsive value cell width; flex-based table scroll
- add a component spec; seed the harness fixture with more demo data
This change is based on the presumption that a signal graph can be significantly large memory-wise sometimes. This is the reason why we don't send the full graph to the FE but rather serialize its values and then lazy load them when they are needed, that is, during value inspection.
Split the `ng` global interface into two interfaces:
* `ExternalCoreGlobalUtils` includes all the functionality which has been shipped in a long-lived Angular version externally and which is subject to the versioning constraints described above.
* `InternalCoreGlobalUtils` includes internal-only functionality which has **not** been shipped in a long-lived Angular version.
This split means that all APIs in `InternalCoreGlobalUtils` can be iterated and evolved at a much faster pace. Angular DevTools can support those features, and we can make breaking changes more-or-less whenever we want. The downside is that external Angular developers cannot take advantage of those APIs or else we would be subject to the same versioning constraint we're trying to avoid here.
This means we can use `InternalCoreGlobalUtils` as a kind of "beta" channel for new DevTools APIs. Once that functionality is validated and the design is stabilized, the feature can be moved into `ExternalCoreGlobalUtils` and made available for external Angular developers when we're ready to commit to the long-lived version constraint. This will hopefully help us strike a better balance between iterating on new APIs quickly and maintaining stable APIs for external Angular users.
Make the `hydration`` property of `DevToolsNode`` optional as frameworks like Client-Only Wiz don't have the same hydration concept as Angular and will not set one for nodes returned from `getComponentForest`.
Set default values for the `directives`, `element`, `hydration`, and `component.isElement` properties of every `ComponentTreeNode` returned by `ng.getComponentForest` for non-Angular apps.
Add an optional injector property to the DevToolsNode and IndexedNode types. Features that require an injector use the injector stored on the node, if it exists, and fall back to getInjectorFromElementNode if it doesn't.
A new ng global function, ng.getComponentForest, is being added to allow the framework to provide the component forest without writing metadata to the DOM. This will allow devtools to display components that don't render any DOM.
Replace the manual injectorsSeen cleanup mechanism with WeakRef and FinalizationRegistry. The old approach worked but coupled cleanup to the UI change detection and required tracking seen injectors across traversal. WeakRef lets the browser handle this naturally, removing the injectorsSeen set and the manual cleanup loop.
Client-Only Wiz doesn't have the concept of a directive. Once the new ng.getComponentForest function is implemented, Client-Only Wiz cowilluld provide `ComponentTreeNode`s without a `directives`` property. This change supports that case by making the `directives` property optional.
The IdentityTracker singleton never deleted entries from its internal
maps (_currentDirectiveId, _currentDirectivePosition, isComponent) for
destroyed directives. This caused the maps to grow monotonically for
the entire DevTools session, retaining references to destroyed component
instances and preventing garbage collection.
The cleanup was intentionally commented out because the profiler needs
to resolve IDs and positions of removed components during recording.
Introduce `setProfilingActive()` to gate cleanup: when profiling is
inactive, removed entries are deleted immediately during `index()`.
When profiling is active, removals are deferred into a `_pendingRemovals`
set and flushed once profiling stops via `capture.ts` start/stop calls.
Depending on the client app version, either show "OnPush" (pre-v22) or "Eager" (v22+); As part of the change, `APP_DATA` root signal has been introduced along with a minor bug fix related to component metadata displaying.
Utilize the new `ng.getControlFlowBlocks` API by refactoring the existing render tree extraction code; Slighly modify @for loop details view
PR Close#66167
- Handle @for data in tree strategies and view extraction
- Show @for details in the UI and property tab
- Persist @for state and update UI accordingly
PR Close#66167
Due to the design of the `ng.getComponent` spy and a race condition where sometimes a `<script>` is added to the test DOM, the `getRootElements` tests used to fail sometimes because those `<script>`s were marked as roots which caused a distortion in the roots count checks. The commit addresses that and also adds an additional test for non-application root Angular components.
Add support for `@defer`-only blocks (previously, they weren't rendered in the component tree at all); Fix declared blocks section in the details
PR Close#66546
Do not call `getSupportedApis` in a prod app since it throws an error due to the absence of `ng`, which prevents the FE from getting the `ngAvailability` message and, respectively, the proper info screen that DevTools cannot be used on a prod app.
When signals throw errors on read, the devtools will show the same error message as the signal custom formatter.
We also don't log errors anymore to the console as those might be surprising to see as errors and are buggy behavior of the devtools.
Show the signal graph button only when a signal-graph-eligible node from the directive explorer is selected; Fix client app error when a `defer` node is selected (related)
Replace URL-based active route detection with direct traversal of the ActivatedRoute tree.
This solution is more reliable than the previous approach because it directly compares router tree configuration objects against the active router instance state with router.routerState.