Repository navigation
analog: fix and improve the Analog inspector from the October 2026 audit #325
Copy link
Copy link
Closed as duplicate
Closed as duplicate
Copy link
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
This comes from a code audit of the Analog inspector, done during a comparison with other devtools in October 2026. Roadmap items live in #310, #311, #312 and #313. Items marked (to confirm) were not reproduced.
Problems
Medium
- Server calls mix across tabs: the call log is a module-level
calls[]andAnalogCallhas nopageId, so calls, duplicate loads, refetches and their lint findings from several tabs end up in one list.pangular:analog-server-callshas nopageargument. Tag browser requests with the page id (a header set by the overlay, or a Referer-to-page map), store it onAnalogCall, add a page filter to the tool and the Server tab, and run duplicate and refetch detection per page (packages/devtools/src/analog-server-log.ts:40-89,packages/devtools/src/rpc/analog-register.ts:312-327). - Lint reads the newest page, not the shown one:
analogLintusesstate.pages[0], while the panel picks its page withhostPageIdbut callsanalog-lintwithout it. A panel docked in tab A can show tab B's hydration errors and restart-needed findings. Add an optionalpageIdtoanalogLint, theanalog-lintRPC andpangular:analog-lint, and passhostPageIdfrom the panel (packages/devtools/src/rpc/analog-tools.ts:665,app/src/pages/analog-inspector.ts:2273,app/src/pages/analog-inspector.ts:2426). - Synchronous rescans on every push:
project()is cached for only 2 s (SCAN_CACHE_MS) and runs on everypush-analogand every panel refresh, which fires 300 ms after any state change. Each scan walks up to 4000 files withreaddirSyncandreadFileSyncand blocks the Vite event loop. Invalidate the cache from Vite's watcher (src/app/pages,src/app/routes,src/server,src/content,vite.config) instead of a TTL, and have the panel refetch lint and render only when calls or pages change (packages/devtools/src/rpc/analog-register.ts:45,packages/devtools/src/rpc/analog-register.ts:197-215,app/src/pages/analog-inspector.ts:2379-2383). - Server functions with type arguments are missed: the regex
=\s*(\w+)\s*\(doesn't matchexport const getX = serverFn<Input>(...), and re-exports are skipped too. Those functions drop out of the list and call names, and the server-without-load lint can fire falsely. Allow(?:<[^>]*>)?before the paren, or parse withts.createSourceFile(packages/devtools/src/rpc/analog-scan.ts:411-413). - Config parsing stops after 4000 characters:
analogConfigreadssource.slice(start, start + 4000), sorouteRules,prerender.routesorapiPrefixpast a largenitroblock are silently ignored. The lazy prerender regex can also pick up aroutes:key outside theprerenderblock. Slice to the matching close paren with depth counting, readroutesonly insideprerender: {...}, and report when the config couldn't be fully parsed (packages/devtools/src/rpc/analog-scan.ts:560,packages/devtools/src/rpc/analog-scan.ts:578-580).
Low
- Server files only looked up in
src/app/pages:serverFileswalkssrc/app/pagesonly, whilerouteFiles()also walksapp/routesandsrc/app/routes..server.tsfiles beside routes there are missed byorphan-server-fileand the existence check inresolveAnalogReport. Walk the same roots asrouteFiles()(packages/devtools/src/rpc/analog-scan.ts:691) (to confirm). - load() payload stringified on every tick:
loadSummaryrunsJSON.stringifytwice (redacted preview and byte count) on every push, even when the data hasn't changed. Cache the summary in aWeakMapkeyed by the data object (packages/devtools/src/analog-runtime.ts:152-166,packages/devtools/src/analog-runtime.ts:299-307). - Report strings have no length limit:
isAnalogReportchecks types and counts only, andredactAnalogReportclipshydrationErrorsonly after redaction.url,load.preview,configPathsentries and chain paths can be any size and are run through regex redaction and copied into shared state. Cap them inisAnalogReportor clip before redaction (url 2000, preview 1000, path 500) (packages/devtools/src/rpc/analog-tools.ts:52-82,packages/devtools/src/analog-redact.ts:10-23). - Analog RPCs missing from
RPC_INSPECTOR: nopush-analog,forget-analog-pageoranalog-*entries. It works only becauseregisterAnalogruns behindon.analogand agent tools fall back on theanalog-prefix. Addpush-analog,forget-analog-page,analog-clear-calls,analog-project,analog-explain-url,analog-lint,analog-render,analog-textandanalog-call-api(packages/devtools/src/config.ts:430,packages/devtools/src/config.ts:611). -
list-pagesleaves out Analog pages:summarizePagesgets components, signals, injectors, NgRx, forms, router, pipes and http, but not analog, so the ids thepageargument ofanalog-current-pageneeds aren't discoverable from Analog reports. Pass the analog pages in (packages/devtools/src/devframe.ts:2912-2925). - Lint badge counts info findings as warnings:
const errors = this.findings().lengthcounts every finding and tones itwarn, so the info-onlyapi-outside-prefixmakes the tab look broken. Count errors and warnings apart, use thebadtone for errors, and leave info out (app/src/pages/analog-inspector.ts:2359,app/src/pages/analog-inspector.ts:2370). - Shadowed-page link only matches
.page.ts:shadowed()pulls the file from the message with/(\/\S+\.page\.ts)/, so.page.analogand.page.agpages are never linked. Add the page file as a structured field on thecontent-shadows-pagefinding instead of parsing the message (app/src/pages/analog-inspector.ts:2518-2523,packages/devtools/src/rpc/analog-scan.ts:1020-1028). - Page chain follows
firstChildonly: files rendered in named or auxiliary outlets never show in the current page chain. Walk every child snapshot and tag each entry with its outlet (packages/devtools/src/analog-runtime.ts:103-121). - Load endpoint URLs aren't encoded:
loadEndpointUrlfills params withoutencodeURIComponent, and the catch-all falls back to the last param value, so explained endpoints are wrong for values with reserved characters or routes with several params plus a catch-all. Encode each value and map the catch-all by its own param name (packages/devtools/src/rpc/analog-tools.ts:137-150).
Improvements
- Server route playground: fill
:paramsfrom the route pattern, edit query, headers and cookies, keep request history per route, show response headers and timing, and copy as curl or fetch. Today the sender takes method, path and a JSON body only (app/src/pages/analog-inspector.ts,packages/devtools/src/rpc/analog-register.ts). - Payload tab: list each TransferState entry with its
load()or server function name (nameServerFnsalready exists), size and whether the browser reused it, and link duplicate-load findings to the key (packages/devtools/src/analog-runtime.ts,packages/devtools/src/rpc/analog-tools.ts,app/src/pages/analog-inspector.ts). - Runtime config view: show
import.meta.envVITE_/ANALOG_keys, NitroruntimeConfigand the resolvedanalog()options, redacted withredaction.secretNames(packages/devtools/src/rpc/analog-scan.ts,packages/devtools/src/rpc/analog-register.ts). - Nitro internals: list Nitro plugins, tasks (run action in
ACTION_TOOLS), storage mounts and cached-route entries behindisr/swrrules, with a purge action (packages/devtools/src/rpc/analog-register.ts,packages/devtools/src/config.ts). - Per-route data inspector: show the full redacted
load()value as a lazy tree on demand through an RPC to the page, not just the 1000-character preview (packages/devtools/src/analog-runtime.ts,app/src/pages/analog-inspector.ts). - Render mode check: fetch a page with
Accept: text/htmlfrom the hub and comparecache-control,x-nitro-prerenderandx-analog-no-ssrwith the configured mode (packages/devtools/src/rpc/analog-tools.ts,app/src/pages/analog-inspector.ts). - Content tab: a frontmatter schema check driven by a config option,
contentFilesSource/injectContentFilesusage, and a rendered markdown preview (packages/devtools/src/rpc/analog-scan.ts,app/src/pages/analog-inspector.ts). - Link a page file to its Vite transform stack (vite-plugin-inspect) so the
.analog/.agcompile and theserverFnid rewrite can be seen (packages/devtools/src/vite.ts,app/src/pages/analog-inspector.ts). - Build analysis: after
analog build, show per-route chunk sizes fromdist/analogand which pages pull which lazy chunks, next to the prerender plan (packages/devtools/src/rpc/analog-scan.ts,app/src/pages/analog-inspector.ts).
Already tracked elsewhere
analog-call-apiaccepts any dev server path, including/@fs/…and?raw: phase 1 of 4: safe by default, open in editor and cheap shell wins #310.- Open in editor from every file path in Routes, Server functions, API routes, Lint and the page chain: phase 1 of 4: safe by default, open in editor and cheap shell wins #310.
- A per-navigation timeline that joins SSR, load, server function calls and browser refetches: phase 3 of 4: a devframe shell as good as Vue and Nuxt DevTools #312 (one timeline) and phase 4 of 4: lead where no Angular devtools goes today #313 (network waterfall).
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