Collapse the five web-vitals trackers into a shared helper - #120
Draft
philipwalton wants to merge 1 commit into
Draft
Collapse the five web-vitals trackers into a shared helper#120philipwalton wants to merge 1 commit into
philipwalton wants to merge 1 commit into
Conversation
The trackCLS/trackFCP/trackINP/trackLCP handlers in log.ts were near-identical blocks differing only in their attribution-param mapping. Extract a generic trackMetric() helper that logs the common metric params and delegates the metric-specific params to a mapper function. Also remove the pointless async keywords (nothing awaits). trackTTFB is intentionally left bespoke: its params differ structurally (conditional navigation-timing block, serverTiming expansion, activation_start), and forcing it into the helper would hurt readability. The emitted beacon params are byte-for-byte identical before and after, including the LCP dynamic fetchpriority hint side effect. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The web-vitals handlers in
src/javascript/log.ts—trackCLS,trackFCP,trackINP,trackLCP— were near-identical ~25-line blocks that differed only in how they map attribution data to log params (recommendations.md #15). Theasynckeywords on them were also pointless: nothing inside them awaits, and nothing awaits them.Root cause
Each metric handler was written by copy-paste: every one registered a callback that calls
log.event(metric.name, {value, metric_rating, metric_value, ...metric-specific params, event_id}), duplicating the common shape five times.What changed
trackMetric(onFn, opts, getAttributionParams)helper that registers the callback and logs the common params, spreading the metric-specific params (returned by the mapper) betweenmetric_valueandevent_id— the exact position they occupied in every original handler.trackCLS,trackFCP,trackINP,trackLCPare now thin wrappers supplying only their mapper (and INP'sdurationThreshold: 16). LCP's dynamic-fetchpriority logic (the/hintsendBeaconside effect anddebug_dfp) lives unchanged inside LCP's mapper and still runs beforelog.event.trackTTFBis intentionally left bespoke: its param order differs (metric_valuebeforemetric_rating,event_idbefore the attribution block), and it conditionally assigns a whole navigation-timing block plusserverTimingexpansion andactivation_start. Forcing it into the helper would hurt readability.asynckeywords (TTFB was already non-async).init()order is untouched — FCP still starts first, with the explanatory comment preserved.trackMetric<T extends MetricWithAttribution, O extends ReportOpts>infers each metric's*MetricWithAttributioncallback type and opts type (e.g. INP'sINPAttributionReportOpts) directly from the passedon*function. Noanyanywhere.Param-equivalence proof (static self-check, old vs. new)
Keys emitted per metric, in order — identical before and after:
value, metric_rating, metric_value, debug_target, event_idvalue, metric_rating, metric_value, original_page_path, debug_ttfb, debug_fb2fcp, event_idvalue, metric_rating, metric_value, debug_target, debug_type, debug_time, debug_delay, debug_processing, debug_presentation, event_idvalue, metric_rating, metric_value, debug_target, debug_url, debug_dfp, debug_ttfb, debug_rld, debug_rlt, debug_erd, event_idAll value expressions (including the
'(not set)'fallbacks and LCP's hit/missdebug_dfp) are unchanged verbatim.Verification
npm run lint— pass (0 errors)npm run types:check— pass (astro check + tsc, 0 errors)npm run test:unit— pass (16 files, 67 tests)npm run build— pass (48 pages)npm test) — ran once in full, then re-ran the two flaky specs in isolation:clearStorage/__resettimeout — notably the "wait until hint has been sent" step passed, confirming the refactored LCP/hintbeacon fires).SPECS=worker,log: 2/2 spec files passed, 100% — including both priority-hints tests and the engagement-time test. The log.ts spec asserts the exact beacon params this refactor must preserve.Codex review
Verdict: REQUEST_CHANGES — overruled, with the disagreement recorded here:
asyncchanges error propagation — a sync throw duringon*registration previously became an unawaited rejected promise (init continued), now it would propagate and skip later trackers. This is technically true but not a real regression: the old behavior was a silent unhandled rejection; web-vitalson*registration doesn't throw synchronously (it feature-detects internally);trackTTFBwas already non-async on main with these exact semantics; and removing the pointlessasyncwas an explicit goal of the change.Please scrutinize
async) matches your intent.🤖 Generated with Claude Code