From 60442785faa65b0b758c8a31c088cc53c1dcb298 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Thu, 28 Nov 2024 15:48:21 +0000 Subject: [PATCH 1/4] feat(nuxt): Expose `vueIntegration` --- packages/nuxt/src/client/index.ts | 1 + packages/nuxt/src/client/vueIntegration.ts | 31 +++++++++++++++++++ .../nuxt/src/runtime/plugins/sentry.client.ts | 9 +++++- packages/vue/src/index.ts | 1 + packages/vue/src/integration.ts | 2 ++ 5 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 packages/nuxt/src/client/vueIntegration.ts diff --git a/packages/nuxt/src/client/index.ts b/packages/nuxt/src/client/index.ts index 849c305a22e3..d476348ed937 100644 --- a/packages/nuxt/src/client/index.ts +++ b/packages/nuxt/src/client/index.ts @@ -2,3 +2,4 @@ export * from '@sentry/vue'; export { init } from './sdk'; export { piniaIntegration } from './piniaIntegration'; +export { vueIntegration } from './vueIntegration'; diff --git a/packages/nuxt/src/client/vueIntegration.ts b/packages/nuxt/src/client/vueIntegration.ts new file mode 100644 index 000000000000..1201d07ee0ba --- /dev/null +++ b/packages/nuxt/src/client/vueIntegration.ts @@ -0,0 +1,31 @@ +import { defineIntegration } from '@sentry/core'; +import type { VueIntegrationOptions } from '@sentry/vue'; + +type Options = Omit< + VueIntegrationOptions, + | 'app' + | 'Vue' + // TODO(v9): Should be removed from parent type so we can remove it here + | 'hooks' + // TODO(v9): Should be removed from parent type so we can remove it here + | 'timeout' + // TODO(v9): Should be removed from parent type so we can remove it here + | 'trackComponents' +>; + +let nuxtVueIntegrationOptions: Options | undefined; + +export const vueIntegration = defineIntegration((options: Options = {}) => { + nuxtVueIntegrationOptions = options; + return { + name: 'NuxtVueIntegration', + }; +}); + +/** + * The vueIntegration exported by the Nuxt SDK does nothing besides storing it's options to the side so we can later pick them up when we add the actual vueIntegration. + * This function allows us to pick up the options. + */ +export function retrieveNuxtVueIntegrationOptions(): Options | undefined { + return nuxtVueIntegrationOptions; +} diff --git a/packages/nuxt/src/runtime/plugins/sentry.client.ts b/packages/nuxt/src/runtime/plugins/sentry.client.ts index b89a2fa87a8d..8661db9ee254 100644 --- a/packages/nuxt/src/runtime/plugins/sentry.client.ts +++ b/packages/nuxt/src/runtime/plugins/sentry.client.ts @@ -1,6 +1,7 @@ import { getClient } from '@sentry/core'; import { browserTracingIntegration, vueIntegration } from '@sentry/vue'; import { defineNuxtPlugin } from 'nuxt/app'; +import { retrieveNuxtVueIntegrationOptions } from '../../client/vueIntegration'; import { reportNuxtError } from '../utils'; // --- Types are copied from @sentry/vue (so it does not need to be exported) --- @@ -53,7 +54,13 @@ export default defineNuxtPlugin({ // Adding the Vue integration without the Vue error handler // Nuxt is registering their own error handler, which is unset after hydration: https://github.com/nuxt/nuxt/blob/d3fdbcaac6cf66d21e25d259390d7824696f1a87/packages/nuxt/src/app/entry.ts#L64-L73 // We don't want to wrap the existing error handler, as it leads to a 500 error: https://github.com/getsentry/sentry-javascript/issues/12515 - sentryClient.addIntegration(vueIntegration({ app: vueApp, attachErrorHandler: false })); + sentryClient.addIntegration( + vueIntegration({ + ...retrieveNuxtVueIntegrationOptions(), + app: vueApp, + attachErrorHandler: false, + }), + ); } }); diff --git a/packages/vue/src/index.ts b/packages/vue/src/index.ts index 096b7a2144e5..7e57d55865f7 100644 --- a/packages/vue/src/index.ts +++ b/packages/vue/src/index.ts @@ -5,4 +5,5 @@ export { browserTracingIntegration } from './browserTracingIntegration'; export { attachErrorHandler } from './errorhandler'; export { createTracingMixins } from './tracing'; export { vueIntegration } from './integration'; +export type { VueIntegrationOptions } from './integration'; export { createSentryPiniaPlugin } from './pinia'; diff --git a/packages/vue/src/integration.ts b/packages/vue/src/integration.ts index 22f394d72720..5c30a956304b 100644 --- a/packages/vue/src/integration.ts +++ b/packages/vue/src/integration.ts @@ -19,6 +19,8 @@ const DEFAULT_CONFIG: VueOptions = { const INTEGRATION_NAME = 'Vue'; +export type VueIntegrationOptions = Partial; + export const vueIntegration = defineIntegration((integrationOptions: Partial = {}) => { return { name: INTEGRATION_NAME, From a061e6917eb3d767cd3ee1ed8a3699c045b334c5 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Fri, 29 Nov 2024 08:54:20 +0000 Subject: [PATCH 2/4] Idk man is this better? --- packages/nuxt/src/client/vueIntegration.ts | 24 ++++++++++--------- .../nuxt/src/runtime/plugins/sentry.client.ts | 7 +++--- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/nuxt/src/client/vueIntegration.ts b/packages/nuxt/src/client/vueIntegration.ts index 1201d07ee0ba..1ad8bd08cb80 100644 --- a/packages/nuxt/src/client/vueIntegration.ts +++ b/packages/nuxt/src/client/vueIntegration.ts @@ -1,4 +1,4 @@ -import { defineIntegration } from '@sentry/core'; +import { GLOBAL_OBJ, defineIntegration } from '@sentry/core'; import type { VueIntegrationOptions } from '@sentry/vue'; type Options = Omit< @@ -13,19 +13,21 @@ type Options = Omit< | 'trackComponents' >; -let nuxtVueIntegrationOptions: Options | undefined; +// Since the options object needs to cross the boundary between some builds (i.e. the nuxt module build and our client +// SDK build) we cannot use a getter that is exported from here. Instead we'll pass the options object through a global +// to the module. +export type GlobalObjWithIntegrationOptions = { _sentryNuxtVueIntegrationOptions?: Options }; +// The vue integration is actually set up in the Sentry Client Module. There it is set up as soon as the nuxt app object is available. +// However, we need to export the vueIntegration from the Client SDK. This means all this integration does is store away +// its options for the Sentry Client Module to pick them up when initializing the actual vueIntegration. + +/** + * Add additional error and span instrumentation specialized for Vue. + */ export const vueIntegration = defineIntegration((options: Options = {}) => { - nuxtVueIntegrationOptions = options; + (GLOBAL_OBJ as GlobalObjWithIntegrationOptions)._sentryNuxtVueIntegrationOptions = options; return { name: 'NuxtVueIntegration', }; }); - -/** - * The vueIntegration exported by the Nuxt SDK does nothing besides storing it's options to the side so we can later pick them up when we add the actual vueIntegration. - * This function allows us to pick up the options. - */ -export function retrieveNuxtVueIntegrationOptions(): Options | undefined { - return nuxtVueIntegrationOptions; -} diff --git a/packages/nuxt/src/runtime/plugins/sentry.client.ts b/packages/nuxt/src/runtime/plugins/sentry.client.ts index 8661db9ee254..39d62737f645 100644 --- a/packages/nuxt/src/runtime/plugins/sentry.client.ts +++ b/packages/nuxt/src/runtime/plugins/sentry.client.ts @@ -1,7 +1,7 @@ -import { getClient } from '@sentry/core'; +import { GLOBAL_OBJ, getClient } from '@sentry/core'; import { browserTracingIntegration, vueIntegration } from '@sentry/vue'; import { defineNuxtPlugin } from 'nuxt/app'; -import { retrieveNuxtVueIntegrationOptions } from '../../client/vueIntegration'; +import type { GlobalObjWithIntegrationOptions } from '../../client/vueIntegration'; import { reportNuxtError } from '../utils'; // --- Types are copied from @sentry/vue (so it does not need to be exported) --- @@ -56,7 +56,8 @@ export default defineNuxtPlugin({ // We don't want to wrap the existing error handler, as it leads to a 500 error: https://github.com/getsentry/sentry-javascript/issues/12515 sentryClient.addIntegration( vueIntegration({ - ...retrieveNuxtVueIntegrationOptions(), + // We pick up the options from the "fake" vueIntegration exported by the SDK. + ...(GLOBAL_OBJ as GlobalObjWithIntegrationOptions)._sentryNuxtVueIntegrationOptions, app: vueApp, attachErrorHandler: false, }), From 0ac81c448a19a378eb23039d7a694f6fe63187a0 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Fri, 29 Nov 2024 08:56:24 +0000 Subject: [PATCH 3/4] Switch e2e tests --- .../test-applications/nuxt-3-min/sentry.client.config.ts | 8 +++++++- .../test-applications/nuxt-3/sentry.client.config.ts | 8 +++++++- .../test-applications/nuxt-4/sentry.client.config.ts | 6 +++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3-min/sentry.client.config.ts b/dev-packages/e2e-tests/test-applications/nuxt-3-min/sentry.client.config.ts index 7547bafa6618..9a9566051452 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3-min/sentry.client.config.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3-min/sentry.client.config.ts @@ -6,5 +6,11 @@ Sentry.init({ dsn: useRuntimeConfig().public.sentry.dsn, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1.0, - trackComponents: true, + integrations: [ + Sentry.vueIntegration({ + tracingOptions: { + trackComponents: true, + }, + }), + ], }); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3/sentry.client.config.ts b/dev-packages/e2e-tests/test-applications/nuxt-3/sentry.client.config.ts index 7547bafa6618..9a9566051452 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3/sentry.client.config.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3/sentry.client.config.ts @@ -6,5 +6,11 @@ Sentry.init({ dsn: useRuntimeConfig().public.sentry.dsn, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1.0, - trackComponents: true, + integrations: [ + Sentry.vueIntegration({ + tracingOptions: { + trackComponents: true, + }, + }), + ], }); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-4/sentry.client.config.ts b/dev-packages/e2e-tests/test-applications/nuxt-4/sentry.client.config.ts index dd2183162db9..e8b628595975 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-4/sentry.client.config.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-4/sentry.client.config.ts @@ -6,7 +6,6 @@ Sentry.init({ dsn: useRuntimeConfig().public.sentry.dsn, tunnel: `http://localhost:3031/`, // proxy server tracesSampleRate: 1.0, - trackComponents: true, integrations: [ Sentry.piniaIntegration(usePinia(), { actionTransformer: action => `Transformed: ${action}`, @@ -15,5 +14,10 @@ Sentry.init({ ...state, }), }), + Sentry.vueIntegration({ + tracingOptions: { + trackComponents: true, + }, + }), ], }); From a7db4e499a4a177c38081b8118037a0d64029711 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Fri, 29 Nov 2024 09:23:03 +0000 Subject: [PATCH 4/4] feat(nuxt): Deprecate `tracingOptions` in favor of `vueIntegration` --- docs/migration/draft-v9-migration-guide.md | 4 ++++ packages/vue/src/sdk.ts | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/migration/draft-v9-migration-guide.md b/docs/migration/draft-v9-migration-guide.md index fb62a6635e0d..cd2eec0ba853 100644 --- a/docs/migration/draft-v9-migration-guide.md +++ b/docs/migration/draft-v9-migration-guide.md @@ -68,6 +68,10 @@ - Deprecated `Request` in favor of `RequestEventData`. +## `@sentry/nuxt` + +- Deprecated `tracingOptions` in `Sentry.init()` in favor of passing the `vueIntegration()` to `Sentry.init({ integrations: [...] })` and setting `tracingOptions` there. + ## `@sentry/vue` - Deprecated `tracingOptions`, `trackComponents`, `timeout`, `hooks` options everywhere other than in the `tracingOptions` option of the `vueIntegration()`. diff --git a/packages/vue/src/sdk.ts b/packages/vue/src/sdk.ts index 54025ea052ee..e5447227fd78 100644 --- a/packages/vue/src/sdk.ts +++ b/packages/vue/src/sdk.ts @@ -8,7 +8,14 @@ import type { Options, TracingOptions } from './types'; * Inits the Vue SDK */ export function init( - config: Partial & { tracingOptions: Partial }> = {}, + config: Partial< + Omit & { + /** + * @deprecated Add the `vueIntegration()` and pass the `tracingOptions` there instead. + */ + tracingOptions: Partial; + } + > = {}, ): Client | undefined { const options = { _metadata: {