Repository navigation
feat(browser): Angular integration (@maple-dev/browser/angular, /angular/server) - #1133
JeremyFunk wants to merge 2 commits into
Confidence 3/5 · 1 issue to address
Confidence 3/5 · needs attention
New span-producing integration in a published SDK; the router state machine is well tested, the zone.js workaround is not complete.
quality 90/100 · 1 warning · tests covered · risk medium · 4/4 new units observable
Adds two Angular subpaths to @maple-dev/browser: router navigation and resolver spans, an ErrorHandler, and an SSR render wrapper that writes Server-Timing. The router bookkeeping holds up under supersede, redirect and skip, but the zone.js workaround only covers the navigation span.
provideMapleTracing()spans each navigation aspageload/navigate, named after the matched route templatetracedResolver(name, fn)spans resolver loading under the navigation;RedirectCommandis not a failureMapleErrorHandlerandreportAngularErrorreport asangular.errortracedRender(req, render)wrapsangularApp.handle()in anssrspan and appends the page'sServer-Timing
Findings
Warning · F1 · tracedResolver ends its span inside NgZone, defeating the zone.js fix
correctness · packages/browser/src/angular/index.ts:121-123
provideMapleTracing ends the navigation span outside Angular's zone (index.ts:53) because, as its own comment says, a span that ends in the zone starts the exporter's flush timer as a zone macrotask and keeps ApplicationRef.isStable false. A resolver's span is not covered: traced runs at navigation.ts:91 and runTraced ends the span at failures.ts:79, both inside the zone the router runs resolvers in, so on a zone.js app every route with a resolver (or any traced call during the navigation) is back to waiting on the export timer after the navigation — the exact behaviour zone.browser.test.ts:37 asserts the fix removes, tested only on a route table with no resolver. The angular.error span has the same problem.
End resolver spans outside the zone as well: keep the `NgZone` captured in `provideMapleTracing` and run resolver span endings (or `tracedResolver`'s whole `traced` call, via `inject(NgZone, { optional: true })?.runOutsideAngular(...)`) through it. Worth one zone.js test with a resolver on the route.
What was checked
- Superseded navigations end through
startNavigation'sinterruptNavigation(navigation.ts:60), so the id check atangular/index.ts:95does not double-end them pathOfon absolute, origin-only,*and relative URLs (server.test.ts:99)- No PII in the new spans:
event.url.split(/[?#]/)[0]andscrubUrlstrip query and hash beforeurl.path
Observability coverage: 4 of 4 changes observable
| Change | Kind | Observable | Evidence |
|---|---|---|---|
Angular router navigations (provideMapleTracing) |
client span | yes | angular/index.ts:68 starts pageload/navigate, ended at :97 by routeTemplate |
Resolver data loading (tracedResolver) |
client span | yes | angular/index.ts:122 delegates to traced (navigation.ts:91) |
Angular errors (MapleErrorHandler, reportAngularError) |
error span | yes | angular/index.ts:134 captureException(error, { name: "angular.error" }) |
Angular SSR render (tracedRender) |
server span | yes | angular/server.ts:24 startActiveSpan("ssr", { attributes }) with url.path |
16f3767 · Updated on every push. Reply "won't fix" to dismiss a finding, or mention @maple to ask about one.
Annotations
Check warning on line 123 in packages/browser/src/angular/index.ts
maple-review-bot / Maple / review
correctness: `tracedResolver` ends its span inside NgZone, defeating the zone.js fix
`provideMapleTracing` ends the navigation span outside Angular's zone (`index.ts:53`) because, as its own comment says, a span that ends in the zone starts the exporter's flush timer as a zone macrotask and keeps `ApplicationRef.isStable` false. A resolver's span is not covered: `traced` runs at `navigation.ts:91` and `runTraced` ends the span at `failures.ts:79`, both inside the zone the router runs resolvers in, so on a zone.js app every route with a resolver (or any `traced` call during the navigation) is back to waiting on the export timer after the navigation — the exact behaviour `zone.browser.test.ts:37` asserts the fix removes, tested only on a route table with no resolver. The `angular.error` span has the same problem.