Skip to content

Commit 51cc215

Browse files
committed
feat(nuxt): Detect the server API with @nuxt/kit 4.6
1 parent d3e5b7b commit 51cc215

13 files changed

Lines changed: 401 additions & 305 deletions

‎packages/nuxt/package.json‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
}
5454
},
5555
"dependencies": {
56-
"@nuxt/kit": "^4.5.2",
56+
"@nuxt/kit": "^4.6.0",
5757
"@sentry/browser": "11.5.0",
5858
"@sentry/cloudflare": "11.5.0",
5959
"@sentry/conventions": "^0.26.0",
@@ -62,8 +62,7 @@
6262
"@sentry/bundler-plugins": "11.5.0",
6363
"@sentry/server-runtime-injection": "11.5.0",
6464
"@sentry/server-utils": "11.5.0",
65-
"@sentry/vue": "11.5.0",
66-
"local-pkg": "^1.1.2"
65+
"@sentry/vue": "11.5.0"
6766
},
6867
"devDependencies": {
6968
"@nuxt/nitro-server": "^3.21.11",

‎packages/nuxt/src/module.ts‎

Lines changed: 9 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,13 @@
1-
import {
2-
addPlugin,
3-
addPluginTemplate,
4-
addServerPlugin,
5-
addTemplate,
6-
addVitePlugin,
7-
createResolver,
8-
defineNuxtModule,
9-
} from '@nuxt/kit';
1+
import { addPlugin, addPluginTemplate, addTemplate, addVitePlugin, createResolver, defineNuxtModule } from '@nuxt/kit';
102
// Needed to make TS evaluate the augmentation of Nitro types (https://github.com/nuxt/nuxt/pull/34039)
113
import type {} from '@nuxt/nitro-server';
124

13-
import { consoleSandbox } from '@sentry/core';
145
import * as path from 'path';
156
import type { SentryNuxtModuleOptions } from './common/types';
16-
import {
17-
addDynamicImportEntryFileWrapper,
18-
addServerConfigShimWithWarning,
19-
addSentryTopImport,
20-
addServerConfigPlugin,
21-
addServerConfigToBuild,
22-
} from './vite/addServerConfig';
23-
import { addDatabaseInstrumentation } from './vite/databaseConfig';
24-
import { addMiddlewareImports, addMiddlewareInstrumentation } from './vite/middlewareConfig';
7+
import { setupNitroServer } from './vite/nitroServer';
258
import { setupOrchestrion } from './vite/orchestrion';
269
import { setupSourceMaps } from './vite/sourceMaps';
27-
import { addStorageInstrumentation } from './vite/storageConfig';
28-
import { addOTelCommonJSImportAlias, findDefaultSdkInitFile, getNitroMajorVersion } from './vite/utils';
10+
import { addOTelCommonJSImportAlias, findDefaultSdkInitFile, resolveServerApi } from './vite/utils';
2911

3012
export type ModuleOptions = SentryNuxtModuleOptions;
3113
type NuxtPageSubset = { file?: string; path: string };
@@ -44,6 +26,8 @@ export default defineNuxtModule<ModuleOptions>({
4426
return;
4527
}
4628

29+
const serverApi = resolveServerApi();
30+
4731
const moduleOptions = {
4832
...moduleOptionsParam,
4933
// oxlint-disable-next-line typescript/no-deprecated -- supported until removal
@@ -91,7 +75,6 @@ export default defineNuxtModule<ModuleOptions>({
9175
}
9276

9377
const serverConfigFile = await findDefaultSdkInitFile('server', nuxt, moduleOptions);
94-
const isNitroV3 = (await getNitroMajorVersion(nuxt.options.rootDir)) >= 3;
9578
const nuxtMajor = parseInt((nuxt as unknown as { _version: string })._version?.split('.')[0] ?? '3', 10);
9679
const isMinNuxtV4 = nuxtMajor >= 4;
9780

@@ -100,43 +83,21 @@ export default defineNuxtModule<ModuleOptions>({
10083
// Cloudflare detection happens inside, keyed off the resolved Nitro preset.
10184
setupOrchestrion(nuxt, !!serverConfigFile, moduleOptions.buildTimeInstrumentation);
10285

103-
// The deprecated inject modes replace the default in-bundle initialization until their removal
104-
const usesDeprecatedInjectMode =
105-
moduleOptions.autoInjectServerSentry === 'top-level-import' ||
106-
moduleOptions.autoInjectServerSentry === 'experimental_dynamic-import';
107-
10886
if (serverConfigFile) {
109-
if (!usesDeprecatedInjectMode) {
110-
addServerConfigPlugin(nuxt, serverConfigFile, !isNitroV3);
111-
}
112-
113-
if (isNitroV3) {
114-
addServerPlugin(moduleDirResolver.resolve('./runtime/plugins/handler.server'));
115-
addServerPlugin(moduleDirResolver.resolve('./runtime/plugins/update-route-name.server'));
116-
} else {
117-
addServerPlugin(moduleDirResolver.resolve('./runtime/plugins/handler-legacy.server'));
118-
addServerPlugin(moduleDirResolver.resolve('./runtime/plugins/update-route-name-legacy.server'));
119-
}
120-
121-
addServerPlugin(moduleDirResolver.resolve('./runtime/plugins/sentry.server'));
87+
setupNitroServer(nuxt, serverApi, serverConfigFile, moduleOptions);
12288

12389
if (isMinNuxtV4) {
12490
addPlugin({ src: moduleDirResolver.resolve('./runtime/plugins/route-detector.server'), mode: 'server' });
12591
} else {
12692
addPlugin({ src: moduleDirResolver.resolve('./runtime/plugins/route-detector-legacy.server'), mode: 'server' });
12793
}
128-
129-
// Preps the middleware instrumentation module.
130-
addMiddlewareImports();
131-
addStorageInstrumentation(nuxt, !isNitroV3);
132-
addDatabaseInstrumentation(nuxt.options.nitro, !isNitroV3, moduleOptions);
13394
}
13495

13596
if (clientConfigFile || serverConfigFile) {
13697
setupSourceMaps(moduleOptions, nuxt, addVitePlugin);
13798
}
13899

139-
addOTelCommonJSImportAlias(nuxt, isNitroV3);
100+
addOTelCommonJSImportAlias(nuxt, serverApi === 'nitro3');
140101

141102
let pagesData: NuxtPageSubset[] = [];
142103

@@ -155,8 +116,8 @@ export default defineNuxtModule<ModuleOptions>({
155116
// Vite virtual plugin (for the Vite SSR build, where addPlugin mode:'server' plugins are bundled)
156117
addVitePlugin({
157118
name: 'sentry-nuxt-pages-data-virtual',
158-
resolveId: id => (id === pagesDataVirtualModuleId ? `\0${pagesDataVirtualModuleId}` : null),
159-
load: id =>
119+
resolveId: (id: string) => (id === pagesDataVirtualModuleId ? `\0${pagesDataVirtualModuleId}` : null),
120+
load: (id: string) =>
160121
id === `\0${pagesDataVirtualModuleId}` ? `export default ${JSON.stringify(pagesData, null, 2)};` : undefined,
161122
});
162123
} else {
@@ -186,56 +147,5 @@ export default defineNuxtModule<ModuleOptions>({
186147
tsConfig.include.push(relativePath);
187148
}
188149
});
189-
190-
nuxt.hooks.hook('nitro:init', nitro => {
191-
if (nuxt.options?._prepare) {
192-
return;
193-
}
194-
195-
if (serverConfigFile) {
196-
addMiddlewareInstrumentation(nitro, isNitroV3);
197-
198-
if (!usesDeprecatedInjectMode) {
199-
addServerConfigShimWithWarning(nitro);
200-
201-
if (moduleOptions.debug) {
202-
consoleSandbox(() => {
203-
// eslint-disable-next-line no-console
204-
console.log(
205-
`[Sentry] Bundled \`${serverConfigFile}\` into the Nitro server build. The SDK initializes itself at server startup — no \`node --import\` preload needed.`,
206-
);
207-
});
208-
}
209-
} else {
210-
consoleSandbox(() => {
211-
// eslint-disable-next-line no-console
212-
console.warn(
213-
`[Sentry] \`autoInjectServerSentry: '${moduleOptions.autoInjectServerSentry}'\` is deprecated and will be removed in a future major version. The Sentry server config is bundled into the Nitro server build by default now. Remove the option to use the default behavior.`,
214-
);
215-
});
216-
217-
if (moduleOptions.autoInjectServerSentry === 'top-level-import') {
218-
// Nitro 3 (in Nuxt 5) is not bundled in dev mode, so there is no build to emit into.
219-
if (!(isNitroV3 && nitro.options.dev)) {
220-
addServerConfigToBuild(moduleOptions, nitro, serverConfigFile);
221-
}
222-
addSentryTopImport(moduleOptions, nitro);
223-
}
224-
225-
if (moduleOptions.autoInjectServerSentry === 'experimental_dynamic-import') {
226-
addDynamicImportEntryFileWrapper(nitro, serverConfigFile, moduleOptions);
227-
228-
if (moduleOptions.debug) {
229-
consoleSandbox(() => {
230-
// eslint-disable-next-line no-console
231-
console.log(
232-
'[Sentry] Wrapping the server entry file with a dynamic `import()`, so Sentry can be preloaded before the server initializes.',
233-
);
234-
});
235-
}
236-
}
237-
}
238-
}
239-
});
240150
},
241151
});

‎packages/nuxt/src/vite/addServerConfig.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { existsSync } from 'node:fs';
22
import { basename } from 'node:path';
33
import { pathToFileURL } from 'node:url';
4-
import { addServerPlugin, addTemplate, createResolver } from '@nuxt/kit';
4+
import { addNitroPlugin, addTemplate, createResolver } from '@nuxt/kit';
55
import type { Nuxt } from '@nuxt/schema';
66
import { consoleSandbox, debug } from '@sentry/core';
77
import * as fs from 'fs';
@@ -132,7 +132,7 @@ export function addServerConfigPlugin(nuxt: Nuxt, serverConfigFile: string, isLe
132132
`import ${JSON.stringify(runtimeFlagsTemplate.dst)};\nimport ${JSON.stringify(configPath)};\nexport default () => {};\n`,
133133
});
134134

135-
addServerPlugin(configPluginTemplate.dst);
135+
addNitroPlugin(configPluginTemplate.dst);
136136

137137
// Nitro v2 treeshakes side-effect-only imports outside its runtime dir, which would silently drop
138138
// the top-level `Sentry.init` and the flag assignments.

‎packages/nuxt/src/vite/databaseConfig.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { addServerPlugin, createResolver } from '@nuxt/kit';
1+
import { addNitroPlugin, createResolver } from '@nuxt/kit';
22
import { consoleSandbox } from '@sentry/core';
33
import type { NitroConfig } from 'nitropack/types';
44
import type { SentryNuxtModuleOptions } from '../common/types';
@@ -43,8 +43,8 @@ export function addDatabaseInstrumentation(
4343
});
4444

4545
if (isLegacyNitro) {
46-
addServerPlugin(createResolver(import.meta.url).resolve('./runtime/plugins/database-legacy.server'));
46+
addNitroPlugin(createResolver(import.meta.url).resolve('./runtime/plugins/database-legacy.server'));
4747
} else {
48-
addServerPlugin(createResolver(import.meta.url).resolve('./runtime/plugins/database.server'));
48+
addNitroPlugin(createResolver(import.meta.url).resolve('./runtime/plugins/database.server'));
4949
}
5050
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import { addNitroPlugin, createResolver } from '@nuxt/kit';
2+
import type { Nuxt } from '@nuxt/schema';
3+
import { consoleSandbox } from '@sentry/core';
4+
import type { Nitro } from 'nitropack/types';
5+
import type { SentryNuxtModuleOptions } from '../common/types';
6+
import {
7+
addDynamicImportEntryFileWrapper,
8+
addSentryTopImport,
9+
addServerConfigPlugin,
10+
addServerConfigShimWithWarning,
11+
addServerConfigToBuild,
12+
} from './addServerConfig';
13+
import { addDatabaseInstrumentation } from './databaseConfig';
14+
import { addMiddlewareImports, addMiddlewareInstrumentation } from './middlewareConfig';
15+
import { addStorageInstrumentation } from './storageConfig';
16+
import type { ServerApi } from './utils';
17+
18+
type NitroModuleOptions = Omit<SentryNuxtModuleOptions, 'experimental_entrypointWrappedFunctions'> &
19+
Required<Pick<SentryNuxtModuleOptions, 'experimental_entrypointWrappedFunctions'>>;
20+
21+
/**
22+
* Sets up the server SDK on the Nitro side: the server config plugin, the server plugins, and the
23+
* middleware, storage and database instrumentation.
24+
*
25+
* A host on the `nuxt` server API runs no Nitro, so it gets none of this. Kit would skip each
26+
* Nitro-only registration there with a `NUXT_B8024` warning.
27+
*/
28+
export function setupNitroServer(
29+
nuxt: Nuxt,
30+
serverApi: ServerApi,
31+
serverConfigFile: string,
32+
moduleOptions: NitroModuleOptions,
33+
): void {
34+
if (serverApi === 'nuxt') {
35+
return;
36+
}
37+
38+
const isNitroV3 = serverApi === 'nitro3';
39+
const moduleDirResolver = createResolver(import.meta.url);
40+
// oxlint-disable-next-line typescript/no-deprecated -- supported until removal
41+
const injectMode = moduleOptions.autoInjectServerSentry;
42+
// The deprecated inject modes replace the default in-bundle initialization until their removal
43+
const deprecatedInjectMode =
44+
injectMode === 'top-level-import' || injectMode === 'experimental_dynamic-import' ? injectMode : undefined;
45+
46+
if (!deprecatedInjectMode) {
47+
addServerConfigPlugin(nuxt, serverConfigFile, !isNitroV3);
48+
}
49+
50+
if (isNitroV3) {
51+
addNitroPlugin(moduleDirResolver.resolve('./runtime/plugins/handler.server'));
52+
addNitroPlugin(moduleDirResolver.resolve('./runtime/plugins/update-route-name.server'));
53+
} else {
54+
addNitroPlugin(moduleDirResolver.resolve('./runtime/plugins/handler-legacy.server'));
55+
addNitroPlugin(moduleDirResolver.resolve('./runtime/plugins/update-route-name-legacy.server'));
56+
}
57+
58+
addNitroPlugin(moduleDirResolver.resolve('./runtime/plugins/sentry.server'));
59+
60+
// Preps the middleware instrumentation module.
61+
addMiddlewareImports();
62+
addStorageInstrumentation(nuxt, !isNitroV3);
63+
addDatabaseInstrumentation(nuxt.options.nitro, !isNitroV3, moduleOptions);
64+
65+
nuxt.hooks.hook('nitro:init', nitro => {
66+
if (nuxt.options?._prepare) {
67+
return;
68+
}
69+
70+
addMiddlewareInstrumentation(nitro, isNitroV3);
71+
72+
if (deprecatedInjectMode) {
73+
setupDeprecatedInjectMode(nitro, deprecatedInjectMode, isNitroV3, serverConfigFile, moduleOptions);
74+
return;
75+
}
76+
77+
addServerConfigShimWithWarning(nitro);
78+
79+
if (moduleOptions.debug) {
80+
consoleSandbox(() => {
81+
// eslint-disable-next-line no-console
82+
console.log(
83+
`[Sentry] Bundled \`${serverConfigFile}\` into the Nitro server build. The SDK initializes itself at server startup — no \`node --import\` preload needed.`,
84+
);
85+
});
86+
}
87+
});
88+
}
89+
90+
function setupDeprecatedInjectMode(
91+
nitro: Nitro,
92+
injectMode: 'top-level-import' | 'experimental_dynamic-import',
93+
isNitroV3: boolean,
94+
serverConfigFile: string,
95+
moduleOptions: NitroModuleOptions,
96+
): void {
97+
consoleSandbox(() => {
98+
// eslint-disable-next-line no-console
99+
console.warn(
100+
`[Sentry] \`autoInjectServerSentry: '${injectMode}'\` is deprecated and will be removed in a future major version. The Sentry server config is bundled into the Nitro server build by default now. Remove the option to use the default behavior.`,
101+
);
102+
});
103+
104+
if (injectMode === 'top-level-import') {
105+
// Nitro 3 (in Nuxt 5) is not bundled in dev mode, so there is no build to emit into.
106+
if (!(isNitroV3 && nitro.options.dev)) {
107+
addServerConfigToBuild(moduleOptions, nitro, serverConfigFile);
108+
}
109+
addSentryTopImport(moduleOptions, nitro);
110+
}
111+
112+
if (injectMode === 'experimental_dynamic-import') {
113+
addDynamicImportEntryFileWrapper(nitro, serverConfigFile, moduleOptions);
114+
115+
if (moduleOptions.debug) {
116+
consoleSandbox(() => {
117+
// eslint-disable-next-line no-console
118+
console.log(
119+
'[Sentry] Wrapping the server entry file with a dynamic `import()`, so Sentry can be preloaded before the server initializes.',
120+
);
121+
});
122+
}
123+
}
124+
}

‎packages/nuxt/src/vite/storageConfig.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { addServerPlugin, createResolver } from '@nuxt/kit';
1+
import { addNitroPlugin, createResolver } from '@nuxt/kit';
22
import type { Nuxt } from '@nuxt/schema';
33
import { addServerTemplate } from '../vendor/server-template';
44

@@ -18,8 +18,8 @@ export function addStorageInstrumentation(nuxt: Nuxt, isLegacyNitro: boolean): v
1818
});
1919

2020
if (isLegacyNitro) {
21-
addServerPlugin(moduleDirResolver.resolve('./runtime/plugins/storage-legacy.server'));
21+
addNitroPlugin(moduleDirResolver.resolve('./runtime/plugins/storage-legacy.server'));
2222
} else {
23-
addServerPlugin(moduleDirResolver.resolve('./runtime/plugins/storage.server'));
23+
addNitroPlugin(moduleDirResolver.resolve('./runtime/plugins/storage.server'));
2424
}
2525
}

0 commit comments

Comments
 (0)