Skip to content

Commit 7839d03

Browse files
authored
fix(tracing): tracing not enabled on the server (#575)
1 parent 096e6a2 commit 7839d03

File tree

4 files changed

+276
-96
lines changed

4 files changed

+276
-96
lines changed

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"version": "7.2.6",
44
"description": "Sentry module for Nuxt.js",
55
"repository": "nuxt-community/sentry-module",
6+
"private": true,
67
"license": "MIT",
78
"contributors": [
89
{
@@ -42,8 +43,8 @@
4243
"lint:fix": "eslint --ext .vue,.js,.ts . --fix",
4344
"lint:fixture": "eslint --ext .vue,.js --no-ignore 'test/fixture/*/.nuxt/sentry.*'",
4445
"release": "release-it",
45-
"test:fixture": "vitest",
46-
"test": "yarn prepack && yarn test:fixture run && yarn lint:fixture && yarn typecheck",
46+
"test": "yarn prepack && vitest run && yarn lint:fixture && yarn typecheck",
47+
"test:watch": "vitest",
4748
"typecheck": "tsc",
4849
"coverage": "codecov"
4950
},

src/kit-shim.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ export interface NuxtModule<T extends ModuleOptions = ModuleOptions> {
5757
}
5858

5959
/** Direct access to the Nuxt context - see https://github.com/unjs/unctx. */
60-
let nuxtCtx: Nuxt | null = null
60+
export const nuxtCtx: { value: Nuxt | null } = {
61+
value: null,
62+
}
6163

6264
// TODO: Use use/tryUse from unctx. https://github.com/unjs/unctx/issues/6
6365

@@ -72,7 +74,7 @@ let nuxtCtx: Nuxt | null = null
7274
* ```
7375
*/
7476
export function useNuxt (): Nuxt {
75-
const instance = nuxtCtx
77+
const instance = nuxtCtx.value
7678
if (!instance) {
7779
throw new Error('Nuxt instance is unavailable!')
7880
}
@@ -93,7 +95,7 @@ export function useNuxt (): Nuxt {
9395
* ```
9496
*/
9597
export function tryUseNuxt (): Nuxt | null {
96-
return nuxtCtx
98+
return nuxtCtx.value
9799
}
98100

99101
// -- Nuxt 2 compatibility shims --
@@ -110,9 +112,9 @@ function nuxt2Shims (nuxt: Nuxt) {
110112
nuxt.hooks = nuxt
111113

112114
// Allow using useNuxt()
113-
if (!nuxtCtx) {
114-
nuxtCtx = nuxt
115-
nuxt.hook('close', () => { nuxtCtx = null })
115+
if (!nuxtCtx.value) {
116+
nuxtCtx.value = nuxt
117+
nuxt.hook('close', () => { nuxtCtx.value = null })
116118
}
117119
}
118120

src/options.ts

Lines changed: 86 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type Sentry from '@sentry/node'
66
import * as PluggableIntegrations from '@sentry/integrations'
77
import type { Options } from '@sentry/types'
88
import type { Replay } from '@sentry/vue'
9-
import type { AllIntegrations, LazyConfiguration, TracingConfiguration } from './types/configuration'
9+
import type { AllIntegrations, ClientIntegrations, LazyConfiguration, TracingConfiguration } from './types/configuration'
1010
import type { ModuleConfiguration } from './types'
1111
import { Nuxt, resolveAlias } from './kit-shim'
1212
import { canInitialize } from './utils'
@@ -77,7 +77,7 @@ async function getApiMethods (packageName: string): Promise<string[]> {
7777
return apiMethods
7878
}
7979

80-
export async function resolveRelease (moduleOptions: ModuleConfiguration): Promise<string | undefined> {
80+
export async function resolveRelease (moduleOptions: Readonly<ModuleConfiguration>): Promise<string | undefined> {
8181
if (!('release' in moduleOptions.config)) {
8282
// Determine "config.release" automatically from local repo if not provided.
8383
try {
@@ -90,39 +90,41 @@ export async function resolveRelease (moduleOptions: ModuleConfiguration): Promi
9090
}
9191
}
9292

93-
function resolveClientLazyOptions (options: ModuleConfiguration, apiMethods: string[], logger: ConsolaInstance) {
94-
if (options.lazy) {
95-
const defaultLazyOptions = {
96-
injectMock: true,
97-
injectLoadHook: false,
98-
mockApiMethods: true,
99-
chunkName: 'sentry',
100-
webpackPrefetch: false,
101-
webpackPreload: false,
102-
}
93+
function resolveClientLazyOptions (options: ModuleConfiguration, apiMethods: string[], logger: ConsolaInstance): void {
94+
if (!options.lazy) {
95+
return
96+
}
10397

104-
options.lazy = defu(options.lazy, defaultLazyOptions)
105-
106-
if (!options.lazy.injectMock) {
107-
options.lazy.mockApiMethods = []
108-
} else if (options.lazy.mockApiMethods === true) {
109-
options.lazy.mockApiMethods = apiMethods
110-
} else if (Array.isArray(options.lazy.mockApiMethods)) {
111-
const mockMethods = options.lazy.mockApiMethods
112-
options.lazy.mockApiMethods = mockMethods.filter(method => apiMethods.includes(method))
113-
const notfoundMethods = mockMethods.filter(method => !apiMethods.includes(method))
114-
if (notfoundMethods.length) {
115-
logger.warn('Some specified methods to mock weren\'t found in @sentry/vue:', notfoundMethods)
116-
}
117-
if (!options.lazy.mockApiMethods.includes('captureException')) {
118-
// always add captureException if a sentry mock is requested
119-
options.lazy.mockApiMethods.push('captureException')
120-
}
98+
const defaultLazyOptions: LazyConfiguration = {
99+
injectMock: true,
100+
injectLoadHook: false,
101+
mockApiMethods: true,
102+
chunkName: 'sentry',
103+
webpackPrefetch: false,
104+
webpackPreload: false,
105+
}
106+
107+
options.lazy = defu(options.lazy, defaultLazyOptions)
108+
109+
if (!options.lazy.injectMock) {
110+
options.lazy.mockApiMethods = []
111+
} else if (options.lazy.mockApiMethods === true) {
112+
options.lazy.mockApiMethods = apiMethods
113+
} else if (Array.isArray(options.lazy.mockApiMethods)) {
114+
const mockMethods = options.lazy.mockApiMethods
115+
options.lazy.mockApiMethods = mockMethods.filter(method => apiMethods.includes(method))
116+
const notfoundMethods = mockMethods.filter(method => !apiMethods.includes(method))
117+
if (notfoundMethods.length) {
118+
logger.warn('Some specified methods to mock weren\'t found in @sentry/vue:', notfoundMethods)
119+
}
120+
if (!options.lazy.mockApiMethods.includes('captureException')) {
121+
// always add captureException if a sentry mock is requested
122+
options.lazy.mockApiMethods.push('captureException')
121123
}
122124
}
123125
}
124126

125-
function resolveTracingOptions (options: ModuleConfiguration, config: NonNullable<ModuleConfiguration['config']>) {
127+
function resolveTracingOptions (options: ModuleConfiguration): void {
126128
if (!options.tracing) {
127129
return
128130
}
@@ -135,16 +137,11 @@ function resolveTracingOptions (options: ModuleConfiguration, config: NonNullabl
135137
},
136138
}
137139

138-
const userOptions = typeof options.tracing === 'boolean' ? {} : options.tracing
139-
const tracingOptions = defu(userOptions, defaultTracingOptions)
140+
options.tracing = defu(options.tracing, defaultTracingOptions)
140141

141-
if (config.tracesSampleRate === undefined) {
142-
config.tracesSampleRate = tracingOptions.tracesSampleRate
142+
if (options.config.tracesSampleRate === undefined) {
143+
options.config.tracesSampleRate = options.tracing.tracesSampleRate
143144
}
144-
145-
options.tracing = tracingOptions
146-
// Enable tracing for `Http` integration.
147-
options.serverIntegrations = defu(options.serverIntegrations, { Http: { tracing: true } })
148145
}
149146

150147
export type ResolvedClientOptions = {
@@ -161,25 +158,23 @@ export type ResolvedClientOptions = {
161158
logMockCalls: boolean
162159
tracing: boolean | TracingConfiguration
163160
initialize: boolean
164-
// TODO Fix this type
165-
integrations: Record<string, unknown>
161+
integrations: ClientIntegrations
166162
}
167163

168-
export async function resolveClientOptions (nuxt: Nuxt, moduleOptions: ModuleConfiguration, logger: ConsolaInstance): Promise<ResolvedClientOptions> {
169-
const options = moduleOptions
170-
let config = defu({}, options.config)
164+
export async function resolveClientOptions (nuxt: Nuxt, moduleOptions: Readonly<ModuleConfiguration>, logger: ConsolaInstance): Promise<ResolvedClientOptions> {
165+
const options: ModuleConfiguration = defu(moduleOptions)
171166

172167
let clientConfigPath: string | undefined
173168
if (typeof (options.clientConfig) === 'string') {
174169
clientConfigPath = resolveAlias(options.clientConfig)
175170
clientConfigPath = relative(nuxt.options.buildDir, clientConfigPath)
176171
} else {
177-
config = defu(options.clientConfig, options.config)
172+
options.config = defu(options.clientConfig, options.config)
178173
}
179174

180175
const apiMethods = await getApiMethods('@sentry/vue')
181176
resolveClientLazyOptions(options, apiMethods, logger)
182-
resolveTracingOptions(options, config)
177+
resolveTracingOptions(options)
183178

184179
for (const name of getIntegrationsKeys(options.clientIntegrations)) {
185180
if (!isBrowserDefaultIntegration(name) && !isBrowserPluggableIntegration(name) && !isBrowserVueIntegration(name)) {
@@ -206,7 +201,7 @@ export async function resolveClientOptions (nuxt: Nuxt, moduleOptions: ModuleCon
206201
runtimeConfigKey: options.runtimeConfigKey,
207202
config: {
208203
dsn: options.dsn,
209-
...config,
204+
...options.config,
210205
},
211206
clientConfigPath,
212207
lazy: options.lazy,
@@ -231,8 +226,24 @@ export type ResolvedServerOptions = {
231226
tracing: ModuleConfiguration['tracing']
232227
}
233228

234-
export async function resolveServerOptions (nuxt: Nuxt, moduleOptions: ModuleConfiguration, logger: ConsolaInstance): Promise<ResolvedServerOptions> {
235-
const options = moduleOptions
229+
export async function resolveServerOptions (nuxt: Nuxt, moduleOptions: Readonly<ModuleConfiguration>, logger: ConsolaInstance): Promise<ResolvedServerOptions> {
230+
const options: ModuleConfiguration = defu(moduleOptions)
231+
232+
if (options.tracing) {
233+
resolveTracingOptions(options)
234+
options.serverIntegrations = defu(options.serverIntegrations, { Http: { tracing: true } })
235+
}
236+
237+
if (typeof (options.serverConfig) === 'string') {
238+
const resolvedPath = resolveAlias(options.serverConfig)
239+
try {
240+
options.serverConfig = (await import(resolvedPath).then(m => m.default || m))()
241+
} catch (error) {
242+
logger.error(`Error handling the serverConfig plugin:\n${error}`)
243+
}
244+
}
245+
246+
options.config = defu(getServerRuntimeConfig(nuxt, options), options.serverConfig, options.config)
236247

237248
for (const name of getIntegrationsKeys(options.serverIntegrations)) {
238249
if (!isServerDefaultIntegration(name) && !isServerPlugabbleIntegration(name)) {
@@ -254,56 +265,43 @@ export async function resolveServerOptions (nuxt: Nuxt, moduleOptions: ModuleCon
254265
}
255266
}
256267

257-
const defaultConfig = {
258-
dsn: options.dsn,
259-
integrations: [
260-
// Automatically instrument Node.js libraries and frameworks
261-
...(options.tracing ? autoDiscoverNodePerformanceMonitoringIntegrations() : []),
262-
...filterDisabledIntegrations(options.serverIntegrations)
263-
.map((name) => {
264-
const opt = options.serverIntegrations[name]
265-
try {
266-
if (isServerDefaultIntegration(name)) {
267-
// @ts-expect-error Some integrations don't take arguments but it doesn't hurt to pass one.
268-
return Object.keys(opt as Record<string, unknown>).length ? new ServerIntegrations[name](opt) : new ServerIntegrations[name]()
269-
} else if (isServerPlugabbleIntegration(name)) {
270-
// @ts-expect-error Some integrations don't take arguments but it doesn't hurt to pass one.
271-
// eslint-disable-next-line import/namespace
272-
return Object.keys(opt as Record<string, unknown>).length ? new PluggableIntegrations[name](opt) : new PluggableIntegrations[name]()
273-
} else {
274-
throw new Error(`Unsupported server integration "${name}"`)
275-
}
276-
} catch (error) {
277-
throw new Error(`Failed initializing server integration "${name}".\n${error}`)
268+
options.config.integrations = [
269+
// Automatically instrument Node.js libraries and frameworks
270+
...(options.tracing ? autoDiscoverNodePerformanceMonitoringIntegrations() : []),
271+
...filterDisabledIntegrations(options.serverIntegrations)
272+
.map((name) => {
273+
const opt = options.serverIntegrations[name]
274+
try {
275+
if (isServerDefaultIntegration(name)) {
276+
// @ts-expect-error Some integrations don't take arguments but it doesn't hurt to pass one.
277+
return Object.keys(opt as Record<string, unknown>).length ? new ServerIntegrations[name](opt) : new ServerIntegrations[name]()
278+
} else if (isServerPlugabbleIntegration(name)) {
279+
// @ts-expect-error Some integrations don't take arguments but it doesn't hurt to pass one.
280+
// eslint-disable-next-line import/namespace
281+
return Object.keys(opt as Record<string, unknown>).length ? new PluggableIntegrations[name](opt) : new PluggableIntegrations[name]()
282+
} else {
283+
throw new Error(`Unsupported server integration "${name}"`)
278284
}
279-
}),
280-
...customIntegrations,
281-
],
282-
}
283-
284-
let serverConfig = options.serverConfig
285-
if (typeof (serverConfig) === 'string') {
286-
const resolvedPath = resolveAlias(serverConfig)
287-
try {
288-
serverConfig = (await import(resolvedPath).then(m => m.default || m))()
289-
} catch (error) {
290-
logger.error(`Error handling the serverConfig plugin:\n${error}`)
291-
}
292-
}
293-
294-
const config = defu(getServerRuntimeConfig(nuxt, options), options.serverConfig, options.config, defaultConfig)
295-
resolveTracingOptions(options, options.config)
285+
} catch (error) {
286+
throw new Error(`Failed initializing server integration "${name}".\n${error}`)
287+
}
288+
}),
289+
...customIntegrations,
290+
]
296291

297292
return {
298-
config,
293+
config: {
294+
dsn: options.dsn,
295+
...options.config,
296+
},
299297
apiMethods: await getApiMethods('@sentry/node'),
300298
lazy: options.lazy,
301299
logMockCalls: options.logMockCalls, // for mocked only
302300
tracing: options.tracing,
303301
}
304302
}
305303

306-
function getServerRuntimeConfig (nuxt: Nuxt, options: ModuleConfiguration): Partial<ModuleConfiguration['config']> | undefined {
304+
function getServerRuntimeConfig (nuxt: Nuxt, options: Readonly<ModuleConfiguration>): Partial<ModuleConfiguration['config']> | undefined {
307305
const { publicRuntimeConfig } = nuxt.options
308306
const { runtimeConfigKey } = options
309307
if (publicRuntimeConfig && typeof (publicRuntimeConfig) !== 'function' && runtimeConfigKey in publicRuntimeConfig) {

0 commit comments

Comments
 (0)