Skip to content

feat(vue,nuxt): Record default UI spans without Options API (mixins) - #24174

Open
s1gr1d wants to merge 2 commits into
developfrom
sig/add-alternative-mixin-implementation
Open

feat(vue,nuxt): Record default UI spans without Options API (mixins)#24174
s1gr1d wants to merge 2 commits into
developfrom
sig/add-alternative-mixin-implementation

Conversation

@s1gr1d

@s1gr1d s1gr1d commented Sep 7, 2026

Copy link
Copy Markdown
Member

Nuxt 5 disables Vue's Options API by default (nuxt/nuxt#35791). That turns app.mixin() into a silent no-op, and every Vue UI span comes from that mixin: Application Render and Vue <Root> disappear with no signal.

When the mixin is dropped, the SDK now wraps app.mount() and calls the same mixin hook bodies, so the default spans stay identical. The Nuxt SDK additionally extends the root span until <Suspense> resolves.

trackComponents still needs the Options API and warns when it is lost. Vue 2 behavior stays unchanged (always needs Options API as it's not possible otherwise).

Closes #23375

Docs follow-up: getsentry/sentry-docs#19290

@s1gr1d
s1gr1d requested a review from a team as a code owner September 7, 2026 12:45
@s1gr1d
s1gr1d requested review from mydea and nicohrubec and removed request for a team September 7, 2026 12:45
@s1gr1d

s1gr1d commented Sep 7, 2026

Copy link
Copy Markdown
Member Author

bugbot run

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 28.8 kB - -
@sentry/browser - with treeshaking flags 27.11 kB - -
@sentry/browser - with treeshaking flags tracing without tracing 27 kB - -
@sentry/browser (incl. Tracing) 49.22 kB - -
@sentry/browser (incl. Tracing + Span Streaming) 49.22 kB - -
@sentry/browser (incl. Tracing, Profiling) 52.12 kB - -
@sentry/browser (incl. Tracing, Replay) 88.76 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 77.95 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 93.44 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 106.37 kB - -
@sentry/browser (incl. Feedback) 46.3 kB - -
@sentry/browser (incl. sendFeedback) 33.86 kB - -
@sentry/browser (incl. FeedbackAsync) 38.97 kB - -
@sentry/browser (incl. Metrics) 29.82 kB - -
@sentry/browser (incl. Logs) 30.09 kB - -
@sentry/browser (incl. Metrics & Logs) 30.75 kB - -
@sentry/react 30.55 kB - -
@sentry/react (incl. Tracing) 51.56 kB - -
@sentry/vue 36.18 kB +0.36% +128 B 🔺
@sentry/vue (incl. Tracing) 51.6 kB +0.25% +125 B 🔺
@sentry/svelte 28.83 kB - -
CDN Bundle 30.55 kB - -
CDN Bundle (incl. Tracing) 49.74 kB - -
CDN Bundle (incl. Logs, Metrics) 32.82 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 51.7 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 73.48 kB - -
CDN Bundle (incl. Tracing, Replay) 87.29 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 89.18 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 93.22 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 95.21 kB - -
CDN Bundle - uncompressed 90.46 kB - -
CDN Bundle (incl. Tracing) - uncompressed 148.17 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 97.03 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 154.14 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 226.29 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 267.76 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 273.71 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 281.46 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 287.4 kB - -
@sentry/nextjs (client) 54.03 kB - -
@sentry/sveltekit (client) 49.65 kB - -
@sentry/core/server 36.99 kB - -
@sentry/core/browser 13.55 kB - -
@sentry/node 127.63 kB +0.02% +21 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 81.58 kB - -
@sentry/node - without tracing 88.71 kB +0.03% +22 B 🔺
@sentry/node - without channel injection 106.9 kB +0.02% +20 B 🔺
@sentry/aws-serverless 97.1 kB +0.03% +26 B 🔺
@sentry/cloudflare (withSentry) - minified 201.95 kB - -
@sentry/cloudflare (withSentry) 502.67 kB - -

View base workflow run

@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.

Reviewed by Cursor Bugbot for commit 7b3c0ee. Configure here.

// page's `<Suspense>` boundary resolves. Both hooks are no-ops on the mixin path (Options
// API enabled), which keeps its historical span boundaries.
nuxtApp.hook('app:suspense:resolve', () => INTERNAL_extendVueRootRenderSpan(vueApp));
nuxtApp.hook('page:finish', () => INTERNAL_extendVueRootRenderSpan(vueApp));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

page:finish reopens root render span

Medium Severity

page:finish runs on every client navigation, and INTERNAL_extendVueRootRenderSpan only no-ops after $_sentryRootComponentSpan is cleared. A navigation inside the debounce window still sees that span, resets the timer, and moves Application Render's end timestamp onto the next page. Fast clicks and navigateTo redirects inflate the pageload child and can end it after the pageload parent.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7b3c0ee. Configure here.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Not reproducible, but hardened anyway (and added a test).

A navigation ends the pageload idle span before the next page's page:finish
fires.

What was true: the guard only checked that the span reference exists, so the first post-navigation page:finish armed one dead timer. It now checks span.isRecording() and drops stale references, with a regression test.

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.

[Nuxt 5] Replace the Vue integration’s reliance on app.mixin()

1 participant