Skip to content

Commit e481548

Browse files
authored
fix: support external configuration in form of *.ts (#639)
1 parent ad424f1 commit e481548

23 files changed

+502
-30
lines changed

.size-limit.cjs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ module.exports = [
44
path: 'size-check/base/.nuxt/dist/client/',
55
gzip: false,
66
},
7+
{
8+
name: 'fixture: replay',
9+
path: 'size-check/replay/.nuxt/dist/client/',
10+
gzip: false,
11+
},
712
{
813
name: 'fixture: lazy',
914
path: 'size-check/lazy/.nuxt/dist/client/',
@@ -19,4 +24,9 @@ module.exports = [
1924
path: 'size-check/lazy+tracing/.nuxt/dist/client/',
2025
gzip: false,
2126
},
27+
{
28+
name: 'fixture: typescript',
29+
path: 'size-check/typescript/.nuxt/dist/client/',
30+
gzip: false,
31+
},
2232
];

package.json

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@
3232
"build": "yarn prepack",
3333
"prepack": "nuxt-module-build build",
3434
"dev:prepare": "nuxt-module-build build --stub",
35-
"dev:fixture": "node ./node_modules/nuxt/bin/nuxt.js -c ./test/fixture/default/nuxt.config.cjs",
36-
"dev:fixture:build": "node ./node_modules/nuxt/bin/nuxt.js build -c ./test/fixture/default/nuxt.config.cjs",
37-
"dev:fixture:start": "node ./node_modules/nuxt/bin/nuxt.js start -c ./test/fixture/default/nuxt.config.cjs",
38-
"dev:generate": "nuxt generate -c ./test/fixture/default/nuxt.config.cjs --force-build",
39-
"analyze": "node ./node_modules/nuxt/bin/nuxt.js build --analyze -c ./test/fixture/default/nuxt.config.cjs",
35+
"dev:fixture": "node ./node_modules/nuxt/bin/nuxt.js -c ./test/fixture/default/nuxt.config",
36+
"dev:fixture:build": "node ./node_modules/nuxt/bin/nuxt.js build -c ./test/fixture/default/nuxt.config",
37+
"dev:fixture:start": "node ./node_modules/nuxt/bin/nuxt.js start -c ./test/fixture/default/nuxt.config",
38+
"dev:generate": "nuxt generate -c ./test/fixture/default/nuxt.config --force-build",
39+
"analyze": "node ./node_modules/nuxt/bin/nuxt.js build --analyze -c ./test/fixture/default/nuxt.config",
4040
"size": "yarn build && cd size-check && yarn build && cd .. && yarn size-limit",
4141
"lint": "eslint --ext .vue,.js,.ts .",
4242
"lint:fix": "eslint --ext .vue,.js,.ts . --fix",
@@ -67,13 +67,15 @@
6767
"consola": "^3.2.3",
6868
"defu": "^6.1.2",
6969
"hash-sum": "^2.0.0",
70+
"jiti": "^1.20.0",
7071
"lodash.mergewith": "^4.6.2",
7172
"mlly": "^1.4.2",
7273
"pathe": "^1.1.1"
7374
},
7475
"devDependencies": {
7576
"@nuxt/module-builder": "0.5.2",
7677
"@nuxt/types": "2.17.2",
78+
"@nuxt/typescript-build": "^3.0.1",
7779
"@nuxtjs/eslint-config-typescript": "12.1.0",
7880
"@nuxtjs/module-test-utils": "1.6.3",
7981
"@release-it/conventional-changelog": "7.0.2",

size-check/package.json

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
"private": true,
33
"scripts": {
44
"build": "run-p build:*",
5-
"build:base": "nuxt build -c ./base/nuxt.config.cjs",
6-
"build:tracing": "nuxt build -c ./tracing/nuxt.config.cjs",
7-
"build:lazy": "nuxt build -c ./lazy/nuxt.config.cjs",
8-
"build:lazy+tracing": "nuxt build -c ./lazy+tracing/nuxt.config.cjs"
5+
"build:base": "nuxt build -c ./base/nuxt.config",
6+
"build:replay": "nuxt build -c ./replay/nuxt.config",
7+
"build:tracing": "nuxt build -c ./tracing/nuxt.config",
8+
"build:lazy": "nuxt build -c ./lazy/nuxt.config",
9+
"build:lazy+tracing": "nuxt build -c ./lazy+tracing/nuxt.config",
10+
"build:typescript": "nuxt build -c ./typescript/nuxt.config"
911
}
1012
}

size-check/replay/nuxt.config.cjs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
const SentryModule = require('../..')
2+
3+
/** @type {import('@nuxt/types').NuxtConfig} */
4+
const config = {
5+
rootDir: __dirname,
6+
telemetry: false,
7+
modules: [
8+
/** @type {import('@nuxt/types').Module} */(/** @type {unknown} */(SentryModule)),
9+
],
10+
sentry: {
11+
dsn: 'https://fe8b7df6ea7042f69d7a97c66c2934f7@sentry.io.nuxt/1429779',
12+
clientIntegrations: {
13+
// Integration from @Sentry/browser package.
14+
TryCatch: { eventTarget: false },
15+
Replay: {},
16+
},
17+
18+
},
19+
}
20+
21+
module.exports = config

size-check/replay/pages/index.vue

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<template>
2+
<div>
3+
<h3>Server-side</h3>
4+
<span id="server-side">{{ serverSentryPresent ? 'Works!' : '$sentry object is missing!' }}</span>
5+
<h3>Client-side</h3>
6+
<span id="client-side">{{ clientSentryPresent ? 'Works!' : '$sentry object is missing!' }}</span>
7+
<p>
8+
<button id="crash-button" @click="crash_me()">
9+
crash me
10+
</button>
11+
</p>
12+
</div>
13+
</template>
14+
15+
<script>
16+
export default {
17+
asyncData ({ $sentry }) {
18+
if (process.server) {
19+
return {
20+
serverSentryPresent: Boolean($sentry?.captureException),
21+
}
22+
}
23+
},
24+
data () {
25+
return {
26+
clientSentryPresent: false,
27+
serverSentryPresent: false,
28+
}
29+
},
30+
created () {
31+
if (process.client) {
32+
this.clientSentryPresent = Boolean(this.$sentry?.captureException)
33+
}
34+
},
35+
}
36+
</script>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { ModuleOptions } from 'src/types'
2+
3+
export default function (): ModuleOptions['serverConfig'] {
4+
return {
5+
beforeSend (event, _hint) {
6+
event.extra = {
7+
foo: '1',
8+
}
9+
return event
10+
},
11+
}
12+
}

size-check/typescript/nuxt.config.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { fileURLToPath } from 'node:url'
2+
import initJiti from 'jiti'
3+
import type { NuxtConfig } from '@nuxt/types'
4+
5+
const jiti = initJiti(fileURLToPath(import.meta.url))
6+
7+
const config: NuxtConfig = {
8+
rootDir: __dirname,
9+
telemetry: false,
10+
buildModules: [
11+
'@nuxt/typescript-build',
12+
],
13+
modules: [
14+
jiti.resolve('../..'),
15+
],
16+
sentry: {
17+
dsn: 'https://fe8b7df6ea7042f69d7a97c66c2934f7@sentry.io.nuxt/1429779',
18+
},
19+
typescript: {
20+
typeCheck: false,
21+
},
22+
}
23+
24+
export default config

size-check/typescript/pages/index.vue

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<template>
2+
<div>
3+
<h3>Server-side</h3>
4+
<span id="server-side">{{ serverSentryPresent ? 'Works!' : '$sentry object is missing!' }}</span>
5+
<h3>Client-side</h3>
6+
<span id="client-side">{{ clientSentryPresent ? 'Works!' : '$sentry object is missing!' }}</span>
7+
<p>
8+
<button id="crash-button" @click="crash_me()">
9+
crash me
10+
</button>
11+
</p>
12+
</div>
13+
</template>
14+
15+
<script lang="ts">
16+
import { defineComponent } from 'vue'
17+
18+
export default defineComponent({
19+
asyncData ({ $sentry, query }) {
20+
if (query.crashOnLoad) {
21+
// @ts-ignore forces a crash
22+
// eslint-disable-next-line no-undef
23+
crashOnLoad()
24+
}
25+
26+
if (process.server) {
27+
return {
28+
serverSentryPresent: Boolean($sentry?.captureException),
29+
}
30+
}
31+
},
32+
data () {
33+
return {
34+
clientSentryPresent: false,
35+
serverSentryPresent: false,
36+
}
37+
},
38+
created () {
39+
if (process.client) {
40+
this.clientSentryPresent = Boolean(this.$sentry?.captureException)
41+
}
42+
},
43+
})
44+
</script>

size-check/typescript/tsconfig.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": "../../tsconfig.json",
3+
"compilerOptions": {
4+
"types": [
5+
"@nuxt/typescript-build",
6+
]
7+
},
8+
}

src/module.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { fileURLToPath } from 'url'
1+
import { fileURLToPath } from 'node:url'
22
import { defu } from 'defu'
33
import { resolvePath } from 'mlly'
44
import type { SentryWebpackPluginOptions } from '@sentry/webpack-plugin'

src/options.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import { fileURLToPath } from 'node:url'
12
import type { ConsolaInstance } from 'consola'
23
import { defu } from 'defu'
4+
import initJiti from 'jiti'
35
import { relative } from 'pathe'
46
import { Integrations as ServerIntegrations, autoDiscoverNodePerformanceMonitoringIntegrations } from '@sentry/node'
57
import type Sentry from '@sentry/node'
@@ -11,6 +13,8 @@ import type { ModuleConfiguration } from './types'
1113
import { Nuxt, resolveAlias } from './kit-shim'
1214
import { canInitialize } from './utils'
1315

16+
const jiti = initJiti(fileURLToPath(import.meta.url))
17+
1418
export interface SentryHandlerProxy {
1519
errorHandler: ReturnType<typeof Sentry.Handlers.errorHandler>
1620
requestHandler: ReturnType<typeof Sentry.Handlers.requestHandler>
@@ -242,7 +246,8 @@ export async function resolveServerOptions (nuxt: Nuxt, moduleOptions: Readonly<
242246
if (typeof (options.serverConfig) === 'string') {
243247
const resolvedPath = resolveAlias(options.serverConfig)
244248
try {
245-
options.serverConfig = (await import(resolvedPath).then(m => m.default || m))()
249+
const mod = jiti(resolvedPath)
250+
options.serverConfig = (mod.default || mod)()
246251
} catch (error) {
247252
logger.error(`Error handling the serverConfig plugin:\n${error}`)
248253
}
@@ -261,7 +266,8 @@ export async function resolveServerOptions (nuxt: Nuxt, moduleOptions: Readonly<
261266
if (options.customServerIntegrations) {
262267
const resolvedPath = resolveAlias(options.customServerIntegrations)
263268
try {
264-
customIntegrations = (await import(resolvedPath).then(m => m.default || m))()
269+
const mod = jiti(resolvedPath)
270+
customIntegrations = (mod.default || mod)()
265271
if (!Array.isArray(customIntegrations)) {
266272
logger.error(`Invalid value returned from customServerIntegrations plugin. Expected an array, got "${typeof (customIntegrations)}".`)
267273
}

test/default.test.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
12
import { fileURLToPath } from 'url'
23
import { dirname } from 'path'
34
import { describe, afterAll, beforeAll, beforeEach, test, expect } from 'vitest'
@@ -20,7 +21,7 @@ describe('Smoke test (default)', () => {
2021
beforeAll(async () => {
2122
await localServer.start(TEST_DSN)
2223
const dsn = localServer.getDsn()
23-
nuxt = (await setup(await loadConfig(__dirname, 'default', { sentry: { dsn } }, { merge: true }))).nuxt
24+
nuxt = (await setup(loadConfig(__dirname, 'default', { sentry: { dsn } }, { merge: true }))).nuxt
2425
browser = await createBrowser()
2526
})
2627

@@ -50,5 +51,26 @@ describe('Smoke test (default)', () => {
5051
expect(errors).toEqual([])
5152
})
5253

54+
test('catches a server crash', async () => {
55+
const page = await browser.newPage()
56+
const response = await page.goto(url('/?crashOnLoad=1'))
57+
expect(response!.status()).toBe(500)
58+
59+
const reports = testkit.reports()
60+
expect(reports).toHaveLength(1)
61+
expect(reports[0].error?.message).toContain('crashOnLoad is not defined')
62+
})
63+
64+
test('catches a client crash', async () => {
65+
const page = await browser.newPage()
66+
await page.goto(url('/'))
67+
68+
expect(await $$('#client-side', page)).toBe('Works!')
69+
await page.click('#crash-button')
70+
const reports = testkit.reports()
71+
expect(reports).toHaveLength(1)
72+
expect(reports[0].error?.message).toContain('crash_me is not a function')
73+
})
74+
5375
// TODO: Add tests for custom integration. Blocked by various sentry-kit bugs reported in its repo.
5476
})

test/fixture/default/pages/index.vue

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,13 @@
1414

1515
<script>
1616
export default {
17-
asyncData ({ $sentry }) {
17+
asyncData ({ $sentry, query }) {
18+
if (query.crashOnLoad) {
19+
// @ts-ignore forces a crash
20+
// eslint-disable-next-line no-undef
21+
crashOnLoad()
22+
}
23+
1824
if (process.server) {
1925
return {
2026
serverSentryPresent: Boolean($sentry?.captureException),
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import type { Context } from '@nuxt/types'
2+
import type { ModuleOptions } from 'src/types'
3+
4+
export default function (_context: Context): ModuleOptions['clientIntegrations'] {
5+
return {}
6+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { ModuleOptions } from 'src/types'
2+
3+
export default function (): ModuleOptions['serverConfig'] {
4+
return {
5+
beforeSend (event, _hint) {
6+
event.extra = {
7+
foo: '1',
8+
}
9+
return event
10+
},
11+
}
12+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { fileURLToPath } from 'node:url'
2+
import initJiti from 'jiti'
3+
import type { NuxtConfig } from '@nuxt/types'
4+
5+
const jiti = initJiti(fileURLToPath(import.meta.url))
6+
7+
const config: NuxtConfig = {
8+
rootDir: __dirname,
9+
telemetry: false,
10+
build: {
11+
terser: false,
12+
},
13+
render: {
14+
resourceHints: false,
15+
},
16+
buildModules: [
17+
'@nuxt/typescript-build',
18+
],
19+
modules: [
20+
jiti.resolve('../../..'),
21+
],
22+
sentry: {
23+
dsn: 'https://fe8b7df6ea7042f69d7a97c66c2934f7@sentry.io.nuxt/1429779',
24+
clientIntegrations: {
25+
// Integration from @Sentry/browser package.
26+
TryCatch: { eventTarget: false },
27+
Replay: {},
28+
},
29+
clientConfig: {
30+
// This sets the sample rate to be 10%. You may want this to be 100% while
31+
// in development and sample at a lower rate in production
32+
replaysSessionSampleRate: 0.1,
33+
// If the entire session is not sampled, use the below sample rate to sample
34+
// sessions when an error occurs.
35+
replaysOnErrorSampleRate: 1.0,
36+
},
37+
customClientIntegrations: '~/config/custom-client-integrations.ts',
38+
serverConfig: '~/config/server.config',
39+
tracing: true,
40+
},
41+
typescript: {
42+
typeCheck: false,
43+
},
44+
}
45+
46+
export default config

0 commit comments

Comments
 (0)