From 1963320dfb1e5b455a0d025d15fe5541df925204 Mon Sep 17 00:00:00 2001 From: s1gr1d <32902192+s1gr1d@users.noreply.github.com> Date: Thu, 16 Jul 2026 13:56:08 +0200 Subject: [PATCH 1/4] feat(nuxt): Add `_experimental.useDiagnosticsChannelInjection` --- .../modules/sentry-server-init.ts | 35 -------- .../nuxt-4-orchestrion/nuxt.config.ts | 46 ++-------- .../nuxt-4-orchestrion/package.json | 3 - .../sentry.server.config.ts | 7 +- .../nuxt-4-orchestrion/server/api/db-mysql.ts | 16 +++- .../tests/build-injection.test.ts | 42 ++++++++++ .../nuxt-4-orchestrion/tests/db.test.ts | 8 +- packages/nuxt/package.json | 1 + packages/nuxt/src/common/types.ts | 18 ++++ packages/nuxt/src/module.ts | 5 ++ packages/nuxt/src/vite/orchestrion.ts | 37 ++++++++ .../nuxt/test/vite/buildOptions.test-d.ts | 3 + packages/nuxt/test/vite/orchestrion.test.ts | 84 +++++++++++++++++++ 13 files changed, 220 insertions(+), 85 deletions(-) delete mode 100644 dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/modules/sentry-server-init.ts create mode 100644 dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/tests/build-injection.test.ts create mode 100644 packages/nuxt/src/vite/orchestrion.ts create mode 100644 packages/nuxt/test/vite/orchestrion.test.ts diff --git a/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/modules/sentry-server-init.ts b/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/modules/sentry-server-init.ts deleted file mode 100644 index 4cd518b88974..000000000000 --- a/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/modules/sentry-server-init.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { existsSync, readFileSync, writeFileSync } from 'node:fs'; -import { createResolver, defineNuxtModule } from '@nuxt/kit'; - -const SERVER_CONFIG_FILENAME = 'sentry.server.config'; - -/** - * Local demo module — NOT part of `@sentry/nuxt`. - * - * The orchestrion bundler approach needs the Sentry init to run inside the - * server build (so the diagnostics-channel subscribers are registered before - * the first request) WITHOUT relying on `node --import`. - */ -export default defineNuxtModule({ - meta: { name: 'sentry-server-init' }, - setup(_options, nuxt) { - nuxt.hooks.hook('nitro:init', nitro => { - nitro.hooks.hook('close', () => { - const entryFilePath = createResolver(nitro.options.output.serverDir).resolve('index.mjs'); - - if (!existsSync(entryFilePath)) { - return; - } - - const topImport = `import './${SERVER_CONFIG_FILENAME}.mjs';\n`; - const data = readFileSync(entryFilePath, 'utf8'); - - if (data.startsWith(topImport)) { - return; - } - - writeFileSync(entryFilePath, topImport + data, 'utf8'); - }); - }); - }, -}); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/nuxt.config.ts b/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/nuxt.config.ts index 4f663643f739..8e7b7a15eedb 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/nuxt.config.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/nuxt.config.ts @@ -1,21 +1,16 @@ -import codeTransformerRollup from '@apm-js-collab/code-transformer-bundler-plugins/rollup'; -import { INSTRUMENTED_MODULE_NAMES, SENTRY_INSTRUMENTATIONS } from '@sentry/server-utils/orchestrion/config'; - -// Tells the SDK the orchestrion bundler transform ran, so `detectOrchestrionSetup()` -// no-ops the runtime diagnostics-channel hook. Injected via `codeTransformerRollup`'s -// `injectDiagnostics` option (sourcemap-safe) instead of a hand-rolled plugin. -const orchestrionBundlerMarker = [ - 'globalThis.__SENTRY_ORCHESTRION__ = (globalThis.__SENTRY_ORCHESTRION__ || {});', - 'globalThis.__SENTRY_ORCHESTRION__.bundler = true;', - '', -].join('\n'); - // https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig({ compatibilityDate: '2025-07-15', devtools: { enabled: true }, - modules: ['@sentry/nuxt/module', './modules/sentry-server-init'], + modules: ['@sentry/nuxt/module'], + + sentry: { + _experimental: { + useDiagnosticsChannelInjection: true, + }, + autoInjectServerSentry: 'top-level-import', + }, runtimeConfig: { public: { @@ -24,29 +19,4 @@ export default defineNuxtConfig({ }, }, }, - - nitro: { - // Nuxt's server is built by Nitro (Rollup), not Vite — so the orchestrion - // code transform has to run as a Nitro Rollup plugin to reach `server/api/*` - // routes. Force-bundle the instrumented deps via `externals.inline`; - // externalized deps are `require()`d from `node_modules` at runtime and never - // pass through the transform. - // - // `standard-as-callback` is ioredis' CJS `export default` helper used by - // `connect()`. Left external, Rollup's interop resolves its `.default` to a - // non-function in the bundle; inlining it alongside ioredis links the - // interop consistently. - externals: { - inline: [...INSTRUMENTED_MODULE_NAMES, 'standard-as-callback'], - }, - rollupConfig: { - plugins: [ - codeTransformerRollup({ - instrumentations: SENTRY_INSTRUMENTATIONS, - injectDiagnostics: () => orchestrionBundlerMarker, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - }) as any, - ], - }, - }, }); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/package.json b/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/package.json index 0ec5d68db235..ca4c3a887d9b 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/package.json +++ b/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/package.json @@ -8,7 +8,6 @@ "generate": "nuxt generate", "preview": "nuxt preview", "start": "node .output/server/index.mjs", - "start:import": "node --import ./.output/server/sentry.server.config.mjs .output/server/index.mjs", "clean": "npx nuxi cleanup", "test": "playwright test", "test:prod": "TEST_ENV=production playwright test", @@ -19,7 +18,6 @@ "//": "Need to use ioredis 5.10.1 because that's the last version before they support tracing channels", "dependencies": { "@sentry/nuxt": "file:../../packed/sentry-nuxt-packed.tgz", - "@sentry/server-utils": "file:../../packed/sentry-server-utils-packed.tgz", "ioredis": "5.10.1", "mysql": "^2.18.1", "nuxt": "^4.4.8", @@ -27,7 +25,6 @@ "vue-router": "^5.1.0" }, "devDependencies": { - "@apm-js-collab/code-transformer-bundler-plugins": "^0.7.0", "@playwright/test": "~1.56.0", "@sentry-internal/test-utils": "link:../../../test-utils" }, diff --git a/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/sentry.server.config.ts b/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/sentry.server.config.ts index 712b60d404b0..b58f42b3aec1 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/sentry.server.config.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/sentry.server.config.ts @@ -1,9 +1,8 @@ import * as Sentry from '@sentry/nuxt'; -// Opt into diagnostics-channel-based auto-instrumentation. This registers the -// channel subscribers (e.g. for `mysql`) that turn the diagnostics-channel -// events — injected at build time by the orchestrion Rollup plugin (see -// `nuxt.config.ts`) — into Sentry spans. Must run before `Sentry.init()`. +// The Nuxt module transforms supported Nitro dependencies when enabled in +// `nuxt.config.ts`. In v10, register Node's matching channel subscribers before +// initializing the SDK so those events become spans. Sentry.experimentalUseDiagnosticsChannelInjection(); Sentry.init({ diff --git a/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/server/api/db-mysql.ts b/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/server/api/db-mysql.ts index 5fbe4ba8f934..5c05d2062105 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/server/api/db-mysql.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/server/api/db-mysql.ts @@ -7,9 +7,19 @@ const connection = mysql.createConnection({ }); export default defineEventHandler(() => { - return new Promise(resolve => { - connection.query('SELECT 1 + 1 AS solution', () => { - connection.query('SELECT NOW()', ['1', '2'], () => { + return new Promise((resolve, reject) => { + connection.query('SELECT 1 + 1 AS solution', error => { + if (error) { + reject(error); + return; + } + + connection.query('SELECT NOW()', ['1', '2'], nestedError => { + if (nestedError) { + reject(nestedError); + return; + } + resolve({ status: 'ok' }); }); }); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/tests/build-injection.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/tests/build-injection.test.ts new file mode 100644 index 000000000000..3cc7b960feee --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/tests/build-injection.test.ts @@ -0,0 +1,42 @@ +import { readFileSync, readdirSync } from 'node:fs'; +import path from 'node:path'; +import { expect, test } from '@playwright/test'; + +function readServerBundle(): string { + const serverDir = path.join(process.cwd(), '.output/server'); + return readdirSync(serverDir, { recursive: true }) + .filter(file => typeof file === 'string' && file.endsWith('.mjs')) + .map(file => readFileSync(path.join(serverDir, file), 'utf8')) + .join('\n'); +} + +function readClientBundle(): string { + const serverDir = path.join(process.cwd(), '.output/public'); + return readdirSync(serverDir, { recursive: true }) + .filter(file => typeof file === 'string' && file.endsWith('.js')) + .map(file => readFileSync(path.join(serverDir, file), 'utf8')) + .join('\n'); +} + +test.describe('Orchestrion build-time injection', () => { + const serverBundle = readServerBundle(); + const clientBundle = readClientBundle(); + + test('force-bundles instrumented dependencies', () => { + expect(serverBundle).not.toMatch(/(from\s*["']mysql["']|require\(["']mysql["']\))/); + expect(serverBundle).not.toMatch(/(from\s*["']ioredis["']|require\(["']ioredis["']\))/); + expect(serverBundle).not.toMatch(/(from\s*["']standard-as-callback["']|require\(["']standard-as-callback["']\))/); + }); + + test('injects diagnostics-channel publishers into the server build', () => { + expect(serverBundle).toContain('__SENTRY_ORCHESTRION__'); + expect(serverBundle).toMatch(/tracingChannel\(["']orchestrion:mysql:query["']\)/); + expect(serverBundle).toMatch(/tracingChannel\(["']orchestrion:ioredis:command["']\)/); + expect(serverBundle).toMatch(/tracingChannel\(["']orchestrion:ioredis:connect["']\)/); + }); + + test('does not inject diagnostics-channel publishers into the client build', () => { + expect(clientBundle).not.toContain('__SENTRY_ORCHESTRION__'); + expect(clientBundle).not.toMatch(/orchestrion:/); + }); +}); diff --git a/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/tests/db.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/tests/db.test.ts index 4aefc07f7c59..2ac8601b0303 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/tests/db.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-4-orchestrion/tests/db.test.ts @@ -8,7 +8,9 @@ test('Instruments ioredis automatically', async ({ baseURL }) => { ); }); - await fetch(`${baseURL}/api/db-ioredis`); + const response = await fetch(`${baseURL}/api/db-ioredis`); + expect(response.status).toBe(200); + expect(await response.text()).toBe('test-value'); const transactionEvent = await transactionEventPromise; @@ -50,7 +52,9 @@ test('Instruments mysql automatically', async ({ baseURL }) => { ); }); - await fetch(`${baseURL}/api/db-mysql`); + const response = await fetch(`${baseURL}/api/db-mysql`); + expect(response.status).toBe(200); + await expect(response.json()).resolves.toEqual({ status: 'ok' }); const transactionEvent = await transactionEventPromise; diff --git a/packages/nuxt/package.json b/packages/nuxt/package.json index afad87708909..abfa925c8ae0 100644 --- a/packages/nuxt/package.json +++ b/packages/nuxt/package.json @@ -60,6 +60,7 @@ "@sentry/node": "10.66.0", "@sentry/node-core": "10.66.0", "@sentry/rollup-plugin": "^5.3.0", + "@sentry/server-utils": "10.65.0", "@sentry/vite-plugin": "^5.3.0", "@sentry/vue": "10.66.0", "local-pkg": "^1.1.2" diff --git a/packages/nuxt/src/common/types.ts b/packages/nuxt/src/common/types.ts index 7c84775e6820..fbc9604cb310 100644 --- a/packages/nuxt/src/common/types.ts +++ b/packages/nuxt/src/common/types.ts @@ -183,6 +183,24 @@ export type SentryNuxtModuleOptions = BuildTimeOptionsBase & { */ enabled?: boolean; + // todo(v11): Update this JSDoc (and remove from experimental) + /** + * Experimental build-time options that may change or be removed without notice. + */ + _experimental?: { + /** + * Enables build-time diagnostics-channel instrumentation for supported dependencies bundled into the Nitro server. + * + * 1. Call `Sentry.experimentalUseDiagnosticsChannelInjection()` just before `Sentry.init()` + * 2. Remove `--import ./.output/server/sentry.server.config.mjs` from your `start`script + * 3. Add `sentry.autoInjectServerSentry: 'top-level-import'` in `nuxt.config.ts` so Sentry's server configuration is automatically imported + * + * @default false + * @experimental May change or be removed in any release. + */ + useDiagnosticsChannelInjection?: boolean; + }; + /** * Options for the Sentry Vite plugin to customize the source maps upload process. * diff --git a/packages/nuxt/src/module.ts b/packages/nuxt/src/module.ts index 72ab409ba384..2dec9c59f2d2 100644 --- a/packages/nuxt/src/module.ts +++ b/packages/nuxt/src/module.ts @@ -13,6 +13,7 @@ import type { SentryNuxtModuleOptions } from './common/types'; import { addDynamicImportEntryFileWrapper, addSentryTopImport, addServerConfigToBuild } from './vite/addServerConfig'; import { addDatabaseInstrumentation } from './vite/databaseConfig'; import { addMiddlewareImports, addMiddlewareInstrumentation } from './vite/middlewareConfig'; +import { setupOrchestrion } from './vite/orchestrion'; import { setupSourceMaps } from './vite/sourceMaps'; import { addStorageInstrumentation } from './vite/storageConfig'; import { addOTelCommonJSImportAlias, findDefaultSdkInitFile, getNitroMajorVersion } from './vite/utils'; @@ -83,6 +84,10 @@ export default defineNuxtModule({ const nuxtMajor = parseInt((nuxt as unknown as { _version: string })._version?.split('.')[0] ?? '3', 10); const isMinNuxtV4 = nuxtMajor >= 4; + if (serverConfigFile && moduleOptions._experimental?.useDiagnosticsChannelInjection) { + setupOrchestrion(nuxt); + } + if (serverConfigFile) { if (isNitroV3) { addServerPlugin(moduleDirResolver.resolve('./runtime/plugins/handler.server')); diff --git a/packages/nuxt/src/vite/orchestrion.ts b/packages/nuxt/src/vite/orchestrion.ts new file mode 100644 index 000000000000..706d33eb5fff --- /dev/null +++ b/packages/nuxt/src/vite/orchestrion.ts @@ -0,0 +1,37 @@ +import type { Nuxt } from '@nuxt/schema'; +import { INSTRUMENTED_MODULE_NAMES } from '@sentry/server-utils/orchestrion/config'; +import { sentryOrchestrionPlugin } from '@sentry/server-utils/orchestrion/rollup'; +import type { NitroConfig } from 'nitropack'; + +// ioredis requires this CommonJS helper to be bundled with it. Leaving it +// external makes Nitro resolve the default export as a namespace object. +const IORedisDependencies = ['standard-as-callback']; + +/** + * Configures Nitro to bundle and transform dependencies that publish tracing + * events through diagnostics channels. + */ +export function setupOrchestrion(nuxt: Nuxt): void { + nuxt.hook('nitro:config', (nitroConfig: NitroConfig) => { + if (nuxt.options?._prepare) { + return; + } + + if (!nitroConfig.rollupConfig) { + nitroConfig.rollupConfig = {}; + } + + if (nitroConfig.rollupConfig.plugins === null || nitroConfig.rollupConfig.plugins === undefined) { + nitroConfig.rollupConfig.plugins = []; + } else if (!Array.isArray(nitroConfig.rollupConfig.plugins)) { + nitroConfig.rollupConfig.plugins = [nitroConfig.rollupConfig.plugins]; + } + + nitroConfig.rollupConfig.plugins.push(sentryOrchestrionPlugin()); + + const externals = (nitroConfig.externals ||= {}); + const inline = externals.inline; + const existingInline = Array.isArray(inline) ? inline : inline ? [inline] : []; + externals.inline = [...new Set([...existingInline, ...INSTRUMENTED_MODULE_NAMES, ...IORedisDependencies])]; + }); +} diff --git a/packages/nuxt/test/vite/buildOptions.test-d.ts b/packages/nuxt/test/vite/buildOptions.test-d.ts index 1ad1560e54ec..0eca417d46f0 100644 --- a/packages/nuxt/test/vite/buildOptions.test-d.ts +++ b/packages/nuxt/test/vite/buildOptions.test-d.ts @@ -54,6 +54,9 @@ describe('Sentry Nuxt build-time options type', () => { // --- SentryNuxtModuleOptions specific options --- enabled: true, + _experimental: { + useDiagnosticsChannelInjection: true, + }, autoInjectServerSentry: 'experimental_dynamic-import', configDir: '~/custom-config', experimental_entrypointWrappedFunctions: ['default', 'handler', 'server', 'customExport'], diff --git a/packages/nuxt/test/vite/orchestrion.test.ts b/packages/nuxt/test/vite/orchestrion.test.ts new file mode 100644 index 000000000000..1d0f8d105627 --- /dev/null +++ b/packages/nuxt/test/vite/orchestrion.test.ts @@ -0,0 +1,84 @@ +import type { Nuxt } from '@nuxt/schema'; +import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; + +const mockSentryOrchestrionPlugin = vi.fn(() => ({ name: 'sentry-orchestrion-plugin' })); + +function createMockNuxt(options: { _prepare?: boolean } = {}) { + const hooks: Record void | Promise>> = {}; + + return { + options: { _prepare: options._prepare ?? false }, + hook: (name: string, callback: (...args: any[]) => void | Promise) => { + hooks[name] = hooks[name] || []; + hooks[name].push(callback); + }, + triggerHook: async (name: string, ...args: any[]) => { + for (const callback of hooks[name] || []) { + await callback(...args); + } + }, + }; +} + +describe('setupOrchestrion', () => { + beforeAll(() => { + vi.doMock('@sentry/server-utils/orchestrion/config', () => ({ + INSTRUMENTED_MODULE_NAMES: ['mysql', 'ioredis'], + })); + vi.doMock('@sentry/server-utils/orchestrion/rollup', () => ({ + sentryOrchestrionPlugin: mockSentryOrchestrionPlugin, + })); + }); + + afterAll(() => { + vi.doUnmock('@sentry/server-utils/orchestrion/config'); + vi.doUnmock('@sentry/server-utils/orchestrion/rollup'); + }); + + beforeEach(() => { + mockSentryOrchestrionPlugin.mockClear(); + }); + + it('adds the transformer and preserves existing inline dependencies', async () => { + const { setupOrchestrion } = await import('../../src/vite/orchestrion'); + const mockNuxt = createMockNuxt(); + const existingPlugin = { name: 'existing-plugin' }; + const nitroConfig = { + rollupConfig: { plugins: existingPlugin }, + externals: { inline: ['ioredis', 'custom-dependency'] }, + }; + + setupOrchestrion(mockNuxt as unknown as Nuxt); + await mockNuxt.triggerHook('nitro:config', nitroConfig); + + expect(mockSentryOrchestrionPlugin).toHaveBeenCalledOnce(); + expect(nitroConfig.rollupConfig.plugins).toEqual([existingPlugin, { name: 'sentry-orchestrion-plugin' }]); + expect(nitroConfig.externals.inline).toEqual(['ioredis', 'custom-dependency', 'mysql', 'standard-as-callback']); + }); + + it('initializes absent Nitro configuration', async () => { + const { setupOrchestrion } = await import('../../src/vite/orchestrion'); + const mockNuxt = createMockNuxt(); + const nitroConfig = {}; + + setupOrchestrion(mockNuxt as unknown as Nuxt); + await mockNuxt.triggerHook('nitro:config', nitroConfig); + + expect(nitroConfig).toEqual({ + rollupConfig: { plugins: [{ name: 'sentry-orchestrion-plugin' }] }, + externals: { inline: ['mysql', 'ioredis', 'standard-as-callback'] }, + }); + }); + + it('does not change Nitro configuration in prepare mode', async () => { + const { setupOrchestrion } = await import('../../src/vite/orchestrion'); + const mockNuxt = createMockNuxt({ _prepare: true }); + const nitroConfig = { rollupConfig: { plugins: [] } }; + + setupOrchestrion(mockNuxt as unknown as Nuxt); + await mockNuxt.triggerHook('nitro:config', nitroConfig); + + expect(mockSentryOrchestrionPlugin).not.toHaveBeenCalled(); + expect(nitroConfig).toEqual({ rollupConfig: { plugins: [] } }); + }); +}); From 35b0785f87b4a1db99ada837885219abde5ae0a4 Mon Sep 17 00:00:00 2001 From: s1gr1d <32902192+s1gr1d@users.noreply.github.com> Date: Fri, 17 Jul 2026 09:43:50 +0200 Subject: [PATCH 2/4] deduplicate --- yarn.lock | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/yarn.lock b/yarn.lock index 381e90c80f85..fbf26dc97ad7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -404,6 +404,16 @@ dependencies: json-schema-to-ts "^3.1.1" +"@apm-js-collab/code-transformer-bundler-plugins@^0.5.0": + version "0.5.0" + resolved "https://registry.yarnpkg.com/@apm-js-collab/code-transformer-bundler-plugins/-/code-transformer-bundler-plugins-0.5.0.tgz#8a08136e8281f7e8e36ac6810d2b122c5917de93" + integrity sha512-YxLBY5nGlurL7QeJLq6e5g0ouBpAp0pwgyA/5rHXEXwhiPLn9ZHbT+Y2LlP90GT872cSocfjWRYu/fnpuBudNQ== + dependencies: + "@apm-js-collab/code-transformer" "^0.15.0" + es-module-lexer "^2.1.0" + magic-string "^0.30.21" + module-details-from-path "^1.0.4" + "@apm-js-collab/code-transformer-bundler-plugins@^0.7.1": version "0.7.1" resolved "https://registry.yarnpkg.com/@apm-js-collab/code-transformer-bundler-plugins/-/code-transformer-bundler-plugins-0.7.1.tgz#f9e7128b87cdabb50e91f2ce3a5c48505b511c41" @@ -414,6 +424,18 @@ magic-string "^0.30.21" module-details-from-path "^1.0.4" +"@apm-js-collab/code-transformer@^0.15.0": + version "0.15.0" + resolved "https://registry.yarnpkg.com/@apm-js-collab/code-transformer/-/code-transformer-0.15.0.tgz#a3a1b6c7b92db16f8277636b4a72a1626e2fa52a" + integrity sha512-XmXYVs8CzJ1Aj79noVbn2weUO/XWtRyURpGqx7aU7DOXlUQhR0WKOQNF0okh7PCeY37vxf7kU3v57OAkEPm3ww== + dependencies: + "@types/estree" "^1.0.8" + astring "^1.9.0" + esquery "^1.7.0" + meriyah "^6.1.4" + semifies "^1.0.0" + source-map "^0.6.0" + "@apm-js-collab/code-transformer@^0.18.0": version "0.18.0" resolved "https://registry.yarnpkg.com/@apm-js-collab/code-transformer/-/code-transformer-0.18.0.tgz#722972c05f04bc37f4bbd5067f42ffd7a990eee9" @@ -426,6 +448,15 @@ semifies "^1.0.0" source-map "^0.6.0" +"@apm-js-collab/tracing-hooks@^0.10.1": + version "0.10.1" + resolved "https://registry.yarnpkg.com/@apm-js-collab/tracing-hooks/-/tracing-hooks-0.10.1.tgz#52a463f6dd03e99582a7dde9816257efabdf63b9" + integrity sha512-w2OWXR7FWrKqSziuE9+QclaZrStxO/8+OwbXM635s/zs0Eez1Qo3ivSPdB2WsaPY/iznKTytONPx/PitD7IXcA== + dependencies: + "@apm-js-collab/code-transformer" "^0.15.0" + debug "^4.4.1" + module-details-from-path "^1.0.4" + "@apm-js-collab/tracing-hooks@^0.13.0": version "0.13.0" resolved "https://registry.yarnpkg.com/@apm-js-collab/tracing-hooks/-/tracing-hooks-0.13.0.tgz#20b2f77ec7a0e5dfd9fbf2215b56e2c2b7f41e4b" @@ -7431,6 +7462,18 @@ resolved "https://registry.yarnpkg.com/@sentry/conventions/-/conventions-0.16.0.tgz#3b58d15714cf44dca1518496c00749eec5525009" integrity sha512-fO9PLmHdVURcSPUpWCItWAtgKiMwGdJHbovoSEyLplX5sxs2ugvI4CBPTrkkgqhObnZOD0CnWBKDzSVQYBKEyQ== +"@sentry/conventions@^0.15.1": + version "0.15.1" + resolved "https://registry.yarnpkg.com/@sentry/conventions/-/conventions-0.15.1.tgz#5b8888862d1e444678938f5afdd7842bca42f7cc" + integrity sha512-ZLP8bRdMON3prWE2tJyImuYscCxdcJeIPIhrOs/rgyFm3C1nCh1B6gdvPj3AZ5zW08oSFFCsq7T+tYEW3h8MNA== + +"@sentry/core@10.65.0": + version "10.65.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-10.65.0.tgz#a98cfd6e138d9658dd42d050902837ff591452e8" + integrity sha512-3aqtmM5NgNGo45BNaaBzi0LPQZAw//NEL4HKS5fXm12pJMa4KEkze8DEKnkTEIrGnWaOJKamecHKlnNg/Mqf/Q== + dependencies: + "@sentry/conventions" "^0.15.1" + "@sentry/node-cpu-profiler@^2.4.2": version "2.4.2" resolved "https://registry.yarnpkg.com/@sentry/node-cpu-profiler/-/node-cpu-profiler-2.4.2.tgz#d0ba01370545297d015df1497daf7f81e27f2ab5" @@ -7489,6 +7532,18 @@ fflate "^0.4.4" mitt "^3.0.0" +"@sentry/server-utils@10.65.0": + version "10.65.0" + resolved "https://registry.yarnpkg.com/@sentry/server-utils/-/server-utils-10.65.0.tgz#7a261a5591c7451a82ce06ed95af5e2c4dbd6ab0" + integrity sha512-80toEFD6s+0Le7jrYB6pHWLF703WSg0WyavAWqrBGWG8JkREHgedAxzFYgoY5GlMI756qk6Ea7UzhJTHd2zAXA== + dependencies: + "@apm-js-collab/code-transformer" "^0.15.0" + "@apm-js-collab/code-transformer-bundler-plugins" "^0.5.0" + "@apm-js-collab/tracing-hooks" "^0.10.1" + "@sentry/conventions" "^0.15.1" + "@sentry/core" "10.65.0" + magic-string "~0.30.0" + "@sentry/vite-plugin@^5.3.0": version "5.3.0" resolved "https://registry.yarnpkg.com/@sentry/vite-plugin/-/vite-plugin-5.3.0.tgz#6cb63bfc1b0d1613a151de456b9c66f6cb21b1d2" From b9749a15ac2b57bc73834d7bb64828b0d7f11008 Mon Sep 17 00:00:00 2001 From: Sigrid <32902192+s1gr1d@users.noreply.github.com> Date: Fri, 17 Jul 2026 10:36:12 +0200 Subject: [PATCH 3/4] Update packages/nuxt/package.json Co-authored-by: Charly Gomez --- packages/nuxt/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nuxt/package.json b/packages/nuxt/package.json index abfa925c8ae0..9f855cc0cb13 100644 --- a/packages/nuxt/package.json +++ b/packages/nuxt/package.json @@ -60,7 +60,7 @@ "@sentry/node": "10.66.0", "@sentry/node-core": "10.66.0", "@sentry/rollup-plugin": "^5.3.0", - "@sentry/server-utils": "10.65.0", + "@sentry/server-utils": "10.66.0", "@sentry/vite-plugin": "^5.3.0", "@sentry/vue": "10.66.0", "local-pkg": "^1.1.2" From 6112c70f5107614c1d269c4a1af54532efc6f7ef Mon Sep 17 00:00:00 2001 From: s1gr1d <32902192+s1gr1d@users.noreply.github.com> Date: Fri, 17 Jul 2026 10:57:02 +0200 Subject: [PATCH 4/4] review comments --- packages/nuxt/src/module.ts | 8 ++-- packages/nuxt/src/vite/orchestrion.ts | 4 +- packages/nuxt/src/vite/sourceMaps.ts | 4 +- yarn.lock | 55 --------------------------- 4 files changed, 6 insertions(+), 65 deletions(-) diff --git a/packages/nuxt/src/module.ts b/packages/nuxt/src/module.ts index 2dec9c59f2d2..4cf39d16cdbc 100644 --- a/packages/nuxt/src/module.ts +++ b/packages/nuxt/src/module.ts @@ -84,11 +84,11 @@ export default defineNuxtModule({ const nuxtMajor = parseInt((nuxt as unknown as { _version: string })._version?.split('.')[0] ?? '3', 10); const isMinNuxtV4 = nuxtMajor >= 4; - if (serverConfigFile && moduleOptions._experimental?.useDiagnosticsChannelInjection) { - setupOrchestrion(nuxt); - } - if (serverConfigFile) { + if (moduleOptions._experimental?.useDiagnosticsChannelInjection) { + setupOrchestrion(nuxt); + } + if (isNitroV3) { addServerPlugin(moduleDirResolver.resolve('./runtime/plugins/handler.server')); addServerPlugin(moduleDirResolver.resolve('./runtime/plugins/update-route-name.server')); diff --git a/packages/nuxt/src/vite/orchestrion.ts b/packages/nuxt/src/vite/orchestrion.ts index 706d33eb5fff..5bc3d3be1a12 100644 --- a/packages/nuxt/src/vite/orchestrion.ts +++ b/packages/nuxt/src/vite/orchestrion.ts @@ -17,9 +17,7 @@ export function setupOrchestrion(nuxt: Nuxt): void { return; } - if (!nitroConfig.rollupConfig) { - nitroConfig.rollupConfig = {}; - } + nitroConfig.rollupConfig ??= {}; if (nitroConfig.rollupConfig.plugins === null || nitroConfig.rollupConfig.plugins === undefined) { nitroConfig.rollupConfig.plugins = []; diff --git a/packages/nuxt/src/vite/sourceMaps.ts b/packages/nuxt/src/vite/sourceMaps.ts index b249b29f4cd3..bba2e6440c46 100644 --- a/packages/nuxt/src/vite/sourceMaps.ts +++ b/packages/nuxt/src/vite/sourceMaps.ts @@ -94,9 +94,7 @@ export function setupSourceMaps( nuxt.hook('nitro:config', (nitroConfig: NitroConfig) => { if (sourceMapsEnabled && !nitroConfig.dev && !nuxt.options?._prepare) { - if (!nitroConfig.rollupConfig) { - nitroConfig.rollupConfig = {}; - } + nitroConfig.rollupConfig ??= {}; if (nitroConfig.rollupConfig.plugins === null || nitroConfig.rollupConfig.plugins === undefined) { nitroConfig.rollupConfig.plugins = []; diff --git a/yarn.lock b/yarn.lock index fbf26dc97ad7..381e90c80f85 100644 --- a/yarn.lock +++ b/yarn.lock @@ -404,16 +404,6 @@ dependencies: json-schema-to-ts "^3.1.1" -"@apm-js-collab/code-transformer-bundler-plugins@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@apm-js-collab/code-transformer-bundler-plugins/-/code-transformer-bundler-plugins-0.5.0.tgz#8a08136e8281f7e8e36ac6810d2b122c5917de93" - integrity sha512-YxLBY5nGlurL7QeJLq6e5g0ouBpAp0pwgyA/5rHXEXwhiPLn9ZHbT+Y2LlP90GT872cSocfjWRYu/fnpuBudNQ== - dependencies: - "@apm-js-collab/code-transformer" "^0.15.0" - es-module-lexer "^2.1.0" - magic-string "^0.30.21" - module-details-from-path "^1.0.4" - "@apm-js-collab/code-transformer-bundler-plugins@^0.7.1": version "0.7.1" resolved "https://registry.yarnpkg.com/@apm-js-collab/code-transformer-bundler-plugins/-/code-transformer-bundler-plugins-0.7.1.tgz#f9e7128b87cdabb50e91f2ce3a5c48505b511c41" @@ -424,18 +414,6 @@ magic-string "^0.30.21" module-details-from-path "^1.0.4" -"@apm-js-collab/code-transformer@^0.15.0": - version "0.15.0" - resolved "https://registry.yarnpkg.com/@apm-js-collab/code-transformer/-/code-transformer-0.15.0.tgz#a3a1b6c7b92db16f8277636b4a72a1626e2fa52a" - integrity sha512-XmXYVs8CzJ1Aj79noVbn2weUO/XWtRyURpGqx7aU7DOXlUQhR0WKOQNF0okh7PCeY37vxf7kU3v57OAkEPm3ww== - dependencies: - "@types/estree" "^1.0.8" - astring "^1.9.0" - esquery "^1.7.0" - meriyah "^6.1.4" - semifies "^1.0.0" - source-map "^0.6.0" - "@apm-js-collab/code-transformer@^0.18.0": version "0.18.0" resolved "https://registry.yarnpkg.com/@apm-js-collab/code-transformer/-/code-transformer-0.18.0.tgz#722972c05f04bc37f4bbd5067f42ffd7a990eee9" @@ -448,15 +426,6 @@ semifies "^1.0.0" source-map "^0.6.0" -"@apm-js-collab/tracing-hooks@^0.10.1": - version "0.10.1" - resolved "https://registry.yarnpkg.com/@apm-js-collab/tracing-hooks/-/tracing-hooks-0.10.1.tgz#52a463f6dd03e99582a7dde9816257efabdf63b9" - integrity sha512-w2OWXR7FWrKqSziuE9+QclaZrStxO/8+OwbXM635s/zs0Eez1Qo3ivSPdB2WsaPY/iznKTytONPx/PitD7IXcA== - dependencies: - "@apm-js-collab/code-transformer" "^0.15.0" - debug "^4.4.1" - module-details-from-path "^1.0.4" - "@apm-js-collab/tracing-hooks@^0.13.0": version "0.13.0" resolved "https://registry.yarnpkg.com/@apm-js-collab/tracing-hooks/-/tracing-hooks-0.13.0.tgz#20b2f77ec7a0e5dfd9fbf2215b56e2c2b7f41e4b" @@ -7462,18 +7431,6 @@ resolved "https://registry.yarnpkg.com/@sentry/conventions/-/conventions-0.16.0.tgz#3b58d15714cf44dca1518496c00749eec5525009" integrity sha512-fO9PLmHdVURcSPUpWCItWAtgKiMwGdJHbovoSEyLplX5sxs2ugvI4CBPTrkkgqhObnZOD0CnWBKDzSVQYBKEyQ== -"@sentry/conventions@^0.15.1": - version "0.15.1" - resolved "https://registry.yarnpkg.com/@sentry/conventions/-/conventions-0.15.1.tgz#5b8888862d1e444678938f5afdd7842bca42f7cc" - integrity sha512-ZLP8bRdMON3prWE2tJyImuYscCxdcJeIPIhrOs/rgyFm3C1nCh1B6gdvPj3AZ5zW08oSFFCsq7T+tYEW3h8MNA== - -"@sentry/core@10.65.0": - version "10.65.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-10.65.0.tgz#a98cfd6e138d9658dd42d050902837ff591452e8" - integrity sha512-3aqtmM5NgNGo45BNaaBzi0LPQZAw//NEL4HKS5fXm12pJMa4KEkze8DEKnkTEIrGnWaOJKamecHKlnNg/Mqf/Q== - dependencies: - "@sentry/conventions" "^0.15.1" - "@sentry/node-cpu-profiler@^2.4.2": version "2.4.2" resolved "https://registry.yarnpkg.com/@sentry/node-cpu-profiler/-/node-cpu-profiler-2.4.2.tgz#d0ba01370545297d015df1497daf7f81e27f2ab5" @@ -7532,18 +7489,6 @@ fflate "^0.4.4" mitt "^3.0.0" -"@sentry/server-utils@10.65.0": - version "10.65.0" - resolved "https://registry.yarnpkg.com/@sentry/server-utils/-/server-utils-10.65.0.tgz#7a261a5591c7451a82ce06ed95af5e2c4dbd6ab0" - integrity sha512-80toEFD6s+0Le7jrYB6pHWLF703WSg0WyavAWqrBGWG8JkREHgedAxzFYgoY5GlMI756qk6Ea7UzhJTHd2zAXA== - dependencies: - "@apm-js-collab/code-transformer" "^0.15.0" - "@apm-js-collab/code-transformer-bundler-plugins" "^0.5.0" - "@apm-js-collab/tracing-hooks" "^0.10.1" - "@sentry/conventions" "^0.15.1" - "@sentry/core" "10.65.0" - magic-string "~0.30.0" - "@sentry/vite-plugin@^5.3.0": version "5.3.0" resolved "https://registry.yarnpkg.com/@sentry/vite-plugin/-/vite-plugin-5.3.0.tgz#6cb63bfc1b0d1613a151de456b9c66f6cb21b1d2"