Repository navigation
injectors: fixes and improvements for the DI inspector #345
Copy link
Copy link
Closed
Labels
bugSomething is broken or shows wrong dataSomething is broken or shows wrong datafeatureA feature request or a pull request that adds oneA feature request or a pull request that adds one
Description
Context
Fixes and improvements from a code audit of the di inspector, done in October 2026. Roadmap work lives in #340, #341, #342 and #343. Items marked (to confirm) were not reproduced; check them before fixing.
Problems
Medium
- Element entries never refresh:
readElementcaches providers, dependencies andprovidedByinelementEntriesfor the life of the element, so a dependency resolved later (lazyinjector.get, or recorded after the profiler caught up) never shows up. Store a cheap version key (provider record count and dependency count) with the entry and re-read when it changes. Update the test "reads element providers and dependencies once per element" (packages/devtools/src/injector-tree.ts:308,:326-327,:377;packages/devtools/src/__tests__/injector-tree.test.ts:146). - Environment injectors off the rendered path are missing:
noteEnvironmentis only fed fromentry.environments, so route injectors for routes not shown,createEnvironmentInjector()injectors and injectors kept alive after navigation never appear. Also discover them from the Router's loaded route configs (_injector/_loadedInjector) and label them "inactive" (packages/devtools/src/injector-tree.ts:390-415,:435).
Low
- Service dependencies skip InjectionTokens:
environmentDependenciesonly handles class tokens (typeof token !== 'function'), souseFactoryInjectionToken providers never list what they inject. Handle created non-multi token records with a factory too, keeping theisCreatedguard (packages/devtools/src/injector-tree.ts:291-292). - No validation on
push-injector-tree: the handler castsrootsandenvironmenttoInjectorTreeNode[]with no shape or size check, then fans them out to the panel and agents. Validate with a valibot schema, cap node count and string lengths, and drop malformed nodes (packages/devtools/src/devframe.ts:1492-1520). - Angular-native overlay keeps a failed push as sent:
pushInjectorTreesetslastInjectorJsonbeforepush-injector-treeand has no try/catch, so a failed push is only retried after the keepalive. Reset it on failure asoverlay.tsdoes, ideally through one shared helper for the three overlays (packages/devtools/src/overlay-angular-native.ts:280-282,packages/devtools/src/overlay.ts:319-323). - NativeScript overlay resends the whole tree on keepalive: it skips
pingKnows('ping-injector-tree')and pushes the full report instead (packages/devtools/src/overlay-nativescript.ts:237, comparepackages/devtools/src/overlay.ts:315). - Zone mode never shown: the collector reports
zoneand the server stores it, but the panel never displays it. Add a badge on the Root node or the toolbar (zoneless / zone.js / zone.js loaded but unused) (app/src/pages/di-inspector.ts,packages/devtools/src/devframe.ts:356). - Panel types drift from the package: the panel's own
DependencyInfohas noprovidedByNameandInjectorPagehas nozone. Import the shared types so type checking catches drift (app/src/pages/di-inspector.ts:21-79,packages/devtools/src/types.ts:224,:241). - Hardcoded caps: the 2000 element cap is hardcoded in the panel text, and "Provided by" chips stop at 12 with no "+N more". Send the cap in the report and add a "+N more" chip (
app/src/pages/di-inspector.ts:193,:1533). - Search results re-announced on every keystroke: the "Provided by" and no-match rows are
role="status". Drop the role from the chip row and announce a debounced summary ("N injectors provide X") through the existingannouncementsignal (app/src/pages/di-inspector.ts:201,:212). - Tokens matched by name only: two tokens with the same class name or InjectionToken description (two
Storeclasses, minified_a) are merged in token queries and panel search. Give tokens a stableWeakMapid and group or disambiguate by it (packages/devtools/src/injector-tree.ts:56-65,packages/devtools/src/rpc/injector-tools.ts:161-165). - Live view hides source data: once a live tree exists, the
get-providersfile:line data is no longer shown. Join live tokens tosourceProvidersby name and show a file:line link in the Provides and Injected here lists (app/src/pages/di-inspector.ts:123,:477-560). - Unknown
provide*()helpers are dropped: source mode maps helpers through the fixedPROVIDE_FN_TO_TOKENtable, soprovideStore,provideFirestoreand custom helpers are invisible. List unknownprovide*()calls in providers arrays andappConfigas "provider function" entries (packages/devtools/src/rpc/get-providers.ts:60-76,:173).
Improvements
- Draw the selected element's resolution path (element injectors up to environment injectors) as a vertical graph, highlighting where the queried token is found or where it would throw NullInjectorError (
app/src/pages/di-inspector.ts). - Show orphaned providers: declared in source (
get-providers) but never created at runtime, and services created in Root that nothing on the page injects (packages/devtools/src/rpc/get-providers.ts,packages/devtools/src/injector-tree.ts,app/src/pages/di-inspector.ts). - Show a warning count badge on the Injectors dock when an optional dependency resolves to "not provided anywhere" (
packages/devtools/src/devframe.ts,app/src/pages/di-inspector.ts).
Already tracked elsewhere
inspect-providerswith no arguments returns JSON cut atMAX_TOOL_CHARS: phase 1 of 4: safe by default and wired into your workflow #340.- The collector walks and stringifies the whole tree every tick; event-driven collection and deltas: phase 3 of 4: a shell you live in #342.
- Ideas already on the roadmap: open in editor (phase 1 of 4: safe by default and wired into your workflow #340), summary-first
inspect-providers(phase 1 of 4: safe by default and wired into your workflow #340), Components and Injectors cross-links (phase 2 of 4: deeper inspection #341), event-driven deltas (phase 3 of 4: a shell you live in #342), provider value peek and anexplain-injectiontool (phase 4 of 4: deeper diagnosis #343).
Generated by Claude Code
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething is broken or shows wrong dataSomething is broken or shows wrong datafeatureA feature request or a pull request that adds oneA feature request or a pull request that adds one
Activity
fix: audit findings for components, injectors, signals, pipes and HTTP (