Skip to content

ref(browser): Replace vendored web-vitals with web-vitals@6 dependency - #23070

Open
logaretm wants to merge 1 commit into
developfrom
awad/webvitals-dep-only
Open

ref(browser): Replace vendored web-vitals with web-vitals@6 dependency#23070
logaretm wants to merge 1 commit into
developfrom
awad/webvitals-dep-only

Conversation

@logaretm

@logaretm logaretm commented Aug 5, 2026

Copy link
Copy Markdown
Member

Replaces the vendored web-vitals fork with web-vitals@6 as a dependency.

No behavior change. browser-utils unit tests and the browser-integration web-vitals suites (LCP/CLS/INP/FCP/TTFB + streamed spans) pass, plus we still gate the bfcache web vitals from being sent, so identical behavior as of today.

A couple of concerns we discussed:

  • Bundle-size: It increased here because this is built against develop, once we add soft navs + bfcache vitals back our vendored version becomes larger and it required a similar size limit bumps in feat(browser): Experimental soft navigation web vitals support #22880
  • Browser Compatibility: The argument I led with was that web vitals as a concept only has a single definition which is the upstream repo, it is not a loose spec, it is a concrete implementation detail that is mostly led by chromium and we already have existing compatibility bugs with existing browsers like Firefox. So given webvitals upstream promises baseline-widely available (~30 months) this should be acceptable for this feature, since web vitals emissions behavior can drift and maintaining this has been a huge overhead for us.

@logaretm logaretm changed the title awad/webvitals dep only ref(browser): Replace vendored web-vitals with web-vitals@6 dependency Aug 5, 2026
@logaretm
logaretm force-pushed the awad/webvitals-dep-only branch from d23f63e to 64997f2 Compare August 5, 2026 16:47
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 30.12 kB - -
@sentry/browser - with treeshaking flags 28.32 kB - -
@sentry/browser (incl. Tracing) 48.82 kB +2.71% +1.28 kB 🔺
@sentry/browser (incl. Tracing + Span Streaming) 48.84 kB +2.75% +1.3 kB 🔺
@sentry/browser (incl. Tracing, Profiling) 53.64 kB +2.59% +1.35 kB 🔺
@sentry/browser (incl. Tracing, Replay) 88.14 kB +1.42% +1.23 kB 🔺
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 77.53 kB +1.58% +1.2 kB 🔺
@sentry/browser (incl. Tracing, Replay with Canvas) 92.84 kB +1.36% +1.24 kB 🔺
@sentry/browser (incl. Tracing, Replay, Feedback) 105.49 kB +1.19% +1.24 kB 🔺
@sentry/browser (incl. Feedback) 47.45 kB - -
@sentry/browser (incl. sendFeedback) 34.96 kB - -
@sentry/browser (incl. FeedbackAsync) 40.1 kB - -
@sentry/browser (incl. Metrics) 31.2 kB - -
@sentry/browser (incl. Logs) 31.41 kB - -
@sentry/browser (incl. Metrics & Logs) 32.11 kB - -
@sentry/react 31.93 kB - -
@sentry/react (incl. Tracing) 50.98 kB +2.4% +1.19 kB 🔺
@sentry/vue 35.2 kB - -
@sentry/vue (incl. Tracing) 50.72 kB +2.45% +1.21 kB 🔺
@sentry/svelte 30.14 kB - -
CDN Bundle 32.13 kB -0.01% -2 B 🔽
CDN Bundle (incl. Tracing) 49.38 kB +3.29% +1.57 kB 🔺
CDN Bundle (incl. Logs, Metrics) 33.65 kB -0.07% -23 B 🔽
CDN Bundle (incl. Tracing, Logs, Metrics) 50.7 kB +3.08% +1.51 kB 🔺
CDN Bundle (incl. Replay, Logs, Metrics) 74.19 kB +1.62% +1.18 kB 🔺
CDN Bundle (incl. Tracing, Replay) 86.92 kB +1.73% +1.48 kB 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 88.2 kB +1.66% +1.44 kB 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) 92.76 kB +1.64% +1.49 kB 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 94.06 kB +1.59% +1.47 kB 🔺
CDN Bundle - uncompressed 95.28 kB +0.01% +6 B 🔺
CDN Bundle (incl. Tracing) - uncompressed 148.14 kB +3.76% +5.37 kB 🔺
CDN Bundle (incl. Logs, Metrics) - uncompressed 99.84 kB -0.07% -60 B 🔽
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 152.12 kB +3.66% +5.37 kB 🔺
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 228.76 kB +1.86% +4.17 kB 🔺
CDN Bundle (incl. Tracing, Replay) - uncompressed 267.4 kB +2.05% +5.37 kB 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 271.36 kB +2.02% +5.37 kB 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 281.1 kB +1.95% +5.36 kB 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 285.05 kB +1.92% +5.36 kB 🔺
@sentry/nextjs (client) 53.53 kB +2.24% +1.17 kB 🔺
@sentry/sveltekit (client) 49.21 kB +2.55% +1.22 kB 🔺
@sentry/core/server 65.54 kB - -
@sentry/core/browser 51.82 kB - -
@sentry/node 120.46 kB - -
@sentry/node/import (ESM hook with diagnostics-channel injection) 0 B added added
@sentry/node - without tracing 84.11 kB - -
@sentry/aws-serverless 92.61 kB - -
@sentry/cloudflare (withSentry) - minified 217.81 kB - -
@sentry/cloudflare (withSentry) 537.06 kB - -

View base workflow run

@logaretm
logaretm force-pushed the awad/webvitals-dep-only branch 4 times, most recently from 43daa35 to b2a21b4 Compare August 5, 2026 19:16
Upstream web-vitals v6 covers the metrics we vendored, so consume it as a
dependency instead of maintaining a ~1.9k-line in-tree copy. instrument.ts
imports the metric functions from the package and observes performance entries
with a local PerformanceObserver; the handful of generic browser helpers still
needed (getNavigationEntry, getVisibilityWatcher, whenIdleOrHidden, etc.) move
to metrics/web-vitals-helpers, and the rest of the vendored code is deleted.

No behavior change: browser-utils unit tests and the browser-integration
web-vitals suites (LCP/CLS/INP/FCP/TTFB + streamed spans) all pass.
@logaretm
logaretm force-pushed the awad/webvitals-dep-only branch from b2a21b4 to a786f2c Compare August 5, 2026 19:44
@logaretm
logaretm marked this pull request as ready for review August 5, 2026 20:03
@logaretm
logaretm requested a review from a team as a code owner August 5, 2026 20:03
@logaretm
logaretm requested review from Lms24 and msonnb and removed request for a team August 5, 2026 20:03

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a786f2c. Configure here.

}
} catch {
// Unsupported entry type; nothing to observe.
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Safari observer sync callback regression

Medium Severity

Replacing the vendored observe helper dropped its Safari workaround that deferred PerformanceObserver callbacks with a microtask. Upstream web-vitals still defers these callbacks, but this local path for paint, longtask, event, and similar entries now runs handlers synchronously on affected Safari versions when buffered: true is used, which can change init-time timing for FP/FCP and related metrics.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit a786f2c. Configure here.

Comment on lines 279 to 288
function instrumentInp(): void {
return onINP(metric => {
triggerHandlers('inp', {
metric,
});
_previousInp = metric;
});
return onINP(
withoutBfcache(metric => {
triggerHandlers('inp', {
metric,
});
_previousInp = metric;
}),
);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The instrumentInp function is incorrectly typed to return void but actually returns a StopListening function, preventing listener cleanup.
Severity: MEDIUM

Suggested Fix

Update the function signature of instrumentInp to correctly declare its return type as StopListening. Change function instrumentInp(): void to function instrumentInp(): StopListening.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: packages/browser-utils/src/metrics/instrument.ts#L279-L288

Potential issue: The `instrumentInp` function is declared with a return type of `void`,
but its implementation returns a `StopListening` function from `onINP(...)`. This type
mismatch causes the returned cleanup function to be discarded when `instrumentInp` is
called within `addMetricObserver`. As a result, the `stopListening` variable becomes
`undefined`, and the cleanup logic in `getCleanupCallback` never executes the
`stopListening()` call. This prevents the INP metric listener from being stopped, unlike
other metrics (`CLS`, `LCP`) which are correctly typed.

Did we get this right? 👍 / 👎 to inform future reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant