Skip to content

http: fixes and improvements for HTTP, SSR and hydration #351

Closed

Description

@erkamyaman

Context

Fixes and improvements from a code audit of http, ssr and hydration, 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

  • compression breaks SSR sniffing and state edits: when compression() is mounted after ssrMiddleware, it wraps res.write outside our wrapper, so the middleware sees gzip or brotli bytes. The render mode sniff then reads garbage, and bufferForEdits joins the chunks as UTF-8, can't find the TransferState script and only notes "could not edit". Nothing checks content-encoding. Check res.getHeader('content-encoding'), skip the sniff and the edit when it is set, and say "mount ssrMiddleware after compression" in the override note and the request detail (packages/devtools/src/ssr-middleware.ts:156-162, ssr-middleware.ts:180-245).
  • network inspector page is too big: network-inspector.ts is 2709 lines, with about 860 lines of inline CSS and the SSR requests, timeline, rules, overrides, hydration and payload sections in one class. Split it into child components (SSR requests, HTTP timeline, rule form, SSR override form, hydration card, payload tree) with a shared store service, and move the styles to a .css file (app/src/pages/network-inspector.ts:1221, network-inspector.ts:2078).

Low

  • client cache check disagrees with the server one: transferCacheEligible ignores credentials: 'include' | 'same-origin', which cacheSkipReason treats as a skip, and can't mirror includePostRequests, includeRequestsWithAuthHeaders or includeHeaders. Share one predicate between both files, and let withPangular({ transferCache }) take the app's HttpTransferCacheOptions (packages/devtools/src/http.ts:170-181, packages/devtools/src/http-cache-reason.ts:24-44).
  • server "cache hit" is misleading: on the server any synchronous, unmocked response gets cacheHit: true, and list-http-calls prints "cache hit", although Angular's transfer cache never replays on the server. Set cacheHit to false on the server and keep cacheStored as the server signal (packages/devtools/src/http.ts:292, packages/devtools/src/rpc/http-tools.ts:43).
  • console patch moves every call site: captureHydrationWarnings replaces console.warn and console.error for good, so Chrome shows every warning and error as coming from http.ts. Add the package output to x_google_ignoreList in the published source maps, and keep a way to undo the patch. phase 3 of 4: a shell you live in #342 plans one console tap for all three patches; this fix should land with it (packages/devtools/src/http.ts:348-366).
  • hydration scan goes stale: after 3 scans the scanner returns its cache while the counter key is unchanged. When ngDevMode is the boolean true, the key is always '', so mismatches from later incremental hydration never show. Each scan also walks up to 50k nodes with SHOW_ALL. Add a MutationObserver flag or a timestamp to the key, walk only elements, text and comments, and rescan after @defer (hydrate on ...) triggers (packages/devtools/src/http-overlay.ts:27-38, packages/devtools/src/http-hydration.ts:45-48).
  • duplicated, unanchored URL glob: globMatch is copied in two files. A pattern matches as a substring anywhere, so /api also matches /apiv2 and URLs whose query string contains /api, with no way to anchor it. Extract one helper, support ^ to anchor at the path start (or match the path only, with an opt-in for the query), and show a live match count in the rule form (packages/devtools/src/http-rules.ts:116, packages/devtools/src/ssr-overrides.ts:61).

Improvements

  • Payload tab extras: per-key size bars, a payload budget warning (for example over 100 KB, or the largest keys), duplicate keys or the same URL stored twice, and a "refetch this key" action (packages/devtools/src/http-payload.ts, app/src/pages/network-inspector.ts).
  • Hydration mismatch diff: show expected and actual side by side, highlight the node through the overlay and jump to the owning component in the component tree (packages/devtools/src/http-hydration.ts, app/src/pages/network-inspector.ts).
  • Duplicate and waterfall lint for client calls: the same GET fired N times in a window, sequential calls that could run in parallel, and calls after the stable point that re-request transfer-cache data, plus a lint-http agent tool listed in config.ts (packages/devtools/src/rpc/http-tools.ts, packages/devtools/src/config.ts).
  • "Copy as fetch" and "Copy as cURL", and replay of a recorded call, with redacted headers (app/src/pages/network-inspector.ts, packages/devtools/src/http-redact.ts).
  • HAR export of a page session, client and server calls plus Server-Timing, with redaction applied (app/src/pages/network-inspector.ts, packages/devtools/src/http-redact.ts).
  • Server-Timing entry for each server HttpClient call (fetch-<n>;desc=url;dur=), so Chrome's own Network timing tab shows the breakdown (packages/devtools/src/ssr-middleware.ts, packages/devtools/src/http.ts).
  • Rule presets: "offline" (status 0 network error through an ErrorEvent-based HttpErrorResponse), "slow 3G" as a global delay, and a flaky mode that fails at a set rate (packages/devtools/src/http-rules.ts, packages/devtools/src/http.ts).
  • Label calls made by httpResource and resource(), and by @defer chunks, so users see which resource issued a request (packages/devtools/src/http.ts).
  • Record native fetch calls (Analog $fetch, third-party SDKs, server fetches in resolvers) in dev on both sides, tagged with side and request id (packages/devtools/src/http.ts, packages/devtools/src/http-rules.ts).

Already tracked elsewhere


Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or shows wrong datafeatureA feature request or a pull request that adds one

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions