From fd49d0b637eabf94e5db243bd77c2a0c0642aad6 Mon Sep 17 00:00:00 2001 From: Sigrid Huemer <32902192+s1gr1d@users.noreply.github.com> Date: Tue, 13 Aug 2024 14:18:43 +0200 Subject: [PATCH] fix(nuxt): Add vue to excludeEsmLoaderHooks array (#13346) fixes https://github.com/getsentry/sentry-javascript/issues/13304 --- packages/nuxt/src/client/sdk.ts | 4 +-- packages/nuxt/src/common/types.ts | 6 ++-- packages/nuxt/src/server/sdk.ts | 24 ++++++++++++++-- packages/nuxt/test/server/sdk.test.ts | 40 +++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 6 deletions(-) diff --git a/packages/nuxt/src/client/sdk.ts b/packages/nuxt/src/client/sdk.ts index 3376e5fdbeb7..d7a59556e37f 100644 --- a/packages/nuxt/src/client/sdk.ts +++ b/packages/nuxt/src/client/sdk.ts @@ -1,14 +1,14 @@ import { getDefaultIntegrations as getBrowserDefaultIntegrations, init as initBrowser } from '@sentry/browser'; import { applySdkMetadata } from '@sentry/core'; import type { Client } from '@sentry/types'; -import type { SentryNuxtOptions } from '../common/types'; +import type { SentryNuxtClientOptions } from '../common/types'; /** * Initializes the client-side of the Nuxt SDK * * @param options Configuration options for the SDK. */ -export function init(options: SentryNuxtOptions): Client | undefined { +export function init(options: SentryNuxtClientOptions): Client | undefined { const sentryOptions = { /* BrowserTracing is added later with the Nuxt client plugin */ defaultIntegrations: [...getBrowserDefaultIntegrations(options)], diff --git a/packages/nuxt/src/common/types.ts b/packages/nuxt/src/common/types.ts index 2a42046b784a..08dc0d2b805e 100644 --- a/packages/nuxt/src/common/types.ts +++ b/packages/nuxt/src/common/types.ts @@ -1,7 +1,9 @@ -import type { init } from '@sentry/vue'; +import type { init as initNode } from '@sentry/node'; +import type { init as initVue } from '@sentry/vue'; // Omitting 'app' as the Nuxt SDK will add the app instance in the client plugin (users do not have to provide this) -export type SentryNuxtOptions = Omit[0] & object, 'app'>; +export type SentryNuxtClientOptions = Omit[0] & object, 'app'>; +export type SentryNuxtServerOptions = Omit[0] & object, 'app'>; type SourceMapsOptions = { /** diff --git a/packages/nuxt/src/server/sdk.ts b/packages/nuxt/src/server/sdk.ts index deadea3c54df..a6599b4ac088 100644 --- a/packages/nuxt/src/server/sdk.ts +++ b/packages/nuxt/src/server/sdk.ts @@ -3,16 +3,17 @@ import { init as initNode } from '@sentry/node'; import type { Client, EventProcessor } from '@sentry/types'; import { logger } from '@sentry/utils'; import { DEBUG_BUILD } from '../common/debug-build'; -import type { SentryNuxtOptions } from '../common/types'; +import type { SentryNuxtServerOptions } from '../common/types'; /** * Initializes the server-side of the Nuxt SDK * * @param options Configuration options for the SDK. */ -export function init(options: SentryNuxtOptions): Client | undefined { +export function init(options: SentryNuxtServerOptions): Client | undefined { const sentryOptions = { ...options, + registerEsmLoaderHooks: mergeRegisterEsmLoaderHooks(options), }; applySdkMetadata(sentryOptions, 'nuxt', ['nuxt', 'node']); @@ -44,3 +45,22 @@ export function init(options: SentryNuxtOptions): Client | undefined { return client; } + +/** + * Adds /vue/ to the registerEsmLoaderHooks options and merges it with the old values in the array if one is defined. + * If the registerEsmLoaderHooks option is already a boolean, nothing is changed. + * + * Only exported for Testing purposes. + */ +export function mergeRegisterEsmLoaderHooks( + options: SentryNuxtServerOptions, +): SentryNuxtServerOptions['registerEsmLoaderHooks'] { + if (typeof options.registerEsmLoaderHooks === 'object' && options.registerEsmLoaderHooks !== null) { + return { + exclude: Array.isArray(options.registerEsmLoaderHooks.exclude) + ? [...options.registerEsmLoaderHooks.exclude, /vue/] + : options.registerEsmLoaderHooks.exclude ?? [/vue/], + }; + } + return options.registerEsmLoaderHooks ?? { exclude: [/vue/] }; +} diff --git a/packages/nuxt/test/server/sdk.test.ts b/packages/nuxt/test/server/sdk.test.ts index 20ec11c33512..7ff68478e36d 100644 --- a/packages/nuxt/test/server/sdk.test.ts +++ b/packages/nuxt/test/server/sdk.test.ts @@ -2,7 +2,9 @@ import * as SentryNode from '@sentry/node'; import type { NodeClient } from '@sentry/node'; import { SDK_VERSION } from '@sentry/node'; import { beforeEach, describe, expect, it, vi } from 'vitest'; +import type { SentryNuxtServerOptions } from '../../src/common/types'; import { init } from '../../src/server'; +import { mergeRegisterEsmLoaderHooks } from '../../src/server/sdk'; const nodeInit = vi.spyOn(SentryNode, 'init'); @@ -82,4 +84,42 @@ describe('Nuxt Server SDK', () => { ); }); }); + + describe('mergeRegisterEsmLoaderHooks', () => { + it('merges exclude array when registerEsmLoaderHooks is an object with an exclude array', () => { + const options: SentryNuxtServerOptions = { + registerEsmLoaderHooks: { exclude: [/test/] }, + }; + const result = mergeRegisterEsmLoaderHooks(options); + expect(result).toEqual({ exclude: [/test/, /vue/] }); + }); + + it('sets exclude array when registerEsmLoaderHooks is an object without an exclude array', () => { + const options: SentryNuxtServerOptions = { + registerEsmLoaderHooks: {}, + }; + const result = mergeRegisterEsmLoaderHooks(options); + expect(result).toEqual({ exclude: [/vue/] }); + }); + + it('returns boolean when registerEsmLoaderHooks is a boolean', () => { + const options1: SentryNuxtServerOptions = { + registerEsmLoaderHooks: true, + }; + const result1 = mergeRegisterEsmLoaderHooks(options1); + expect(result1).toBe(true); + + const options2: SentryNuxtServerOptions = { + registerEsmLoaderHooks: false, + }; + const result2 = mergeRegisterEsmLoaderHooks(options2); + expect(result2).toBe(false); + }); + + it('sets exclude array when registerEsmLoaderHooks is undefined', () => { + const options: SentryNuxtServerOptions = {}; + const result = mergeRegisterEsmLoaderHooks(options); + expect(result).toEqual({ exclude: [/vue/] }); + }); + }); });