Skip to content

Commit

Permalink
fix: support external configuration in form of *.ts (#639)
Browse files Browse the repository at this point in the history
  • Loading branch information
rchl committed Nov 13, 2023
1 parent ad424f1 commit e481548
Show file tree
Hide file tree
Showing 23 changed files with 502 additions and 30 deletions.
10 changes: 10 additions & 0 deletions .size-limit.cjs
Expand Up @@ -4,6 +4,11 @@ module.exports = [
path: 'size-check/base/.nuxt/dist/client/',
gzip: false,
},
{
name: 'fixture: replay',
path: 'size-check/replay/.nuxt/dist/client/',
gzip: false,
},
{
name: 'fixture: lazy',
path: 'size-check/lazy/.nuxt/dist/client/',
Expand All @@ -19,4 +24,9 @@ module.exports = [
path: 'size-check/lazy+tracing/.nuxt/dist/client/',
gzip: false,
},
{
name: 'fixture: typescript',
path: 'size-check/typescript/.nuxt/dist/client/',
gzip: false,
},
];
12 changes: 7 additions & 5 deletions package.json
Expand Up @@ -32,11 +32,11 @@
"build": "yarn prepack",
"prepack": "nuxt-module-build build",
"dev:prepare": "nuxt-module-build build --stub",
"dev:fixture": "node ./node_modules/nuxt/bin/nuxt.js -c ./test/fixture/default/nuxt.config.cjs",
"dev:fixture:build": "node ./node_modules/nuxt/bin/nuxt.js build -c ./test/fixture/default/nuxt.config.cjs",
"dev:fixture:start": "node ./node_modules/nuxt/bin/nuxt.js start -c ./test/fixture/default/nuxt.config.cjs",
"dev:generate": "nuxt generate -c ./test/fixture/default/nuxt.config.cjs --force-build",
"analyze": "node ./node_modules/nuxt/bin/nuxt.js build --analyze -c ./test/fixture/default/nuxt.config.cjs",
"dev:fixture": "node ./node_modules/nuxt/bin/nuxt.js -c ./test/fixture/default/nuxt.config",
"dev:fixture:build": "node ./node_modules/nuxt/bin/nuxt.js build -c ./test/fixture/default/nuxt.config",
"dev:fixture:start": "node ./node_modules/nuxt/bin/nuxt.js start -c ./test/fixture/default/nuxt.config",
"dev:generate": "nuxt generate -c ./test/fixture/default/nuxt.config --force-build",
"analyze": "node ./node_modules/nuxt/bin/nuxt.js build --analyze -c ./test/fixture/default/nuxt.config",
"size": "yarn build && cd size-check && yarn build && cd .. && yarn size-limit",
"lint": "eslint --ext .vue,.js,.ts .",
"lint:fix": "eslint --ext .vue,.js,.ts . --fix",
Expand Down Expand Up @@ -67,13 +67,15 @@
"consola": "^3.2.3",
"defu": "^6.1.2",
"hash-sum": "^2.0.0",
"jiti": "^1.20.0",
"lodash.mergewith": "^4.6.2",
"mlly": "^1.4.2",
"pathe": "^1.1.1"
},
"devDependencies": {
"@nuxt/module-builder": "0.5.2",
"@nuxt/types": "2.17.2",
"@nuxt/typescript-build": "^3.0.1",
"@nuxtjs/eslint-config-typescript": "12.1.0",
"@nuxtjs/module-test-utils": "1.6.3",
"@release-it/conventional-changelog": "7.0.2",
Expand Down
10 changes: 6 additions & 4 deletions size-check/package.json
Expand Up @@ -2,9 +2,11 @@
"private": true,
"scripts": {
"build": "run-p build:*",
"build:base": "nuxt build -c ./base/nuxt.config.cjs",
"build:tracing": "nuxt build -c ./tracing/nuxt.config.cjs",
"build:lazy": "nuxt build -c ./lazy/nuxt.config.cjs",
"build:lazy+tracing": "nuxt build -c ./lazy+tracing/nuxt.config.cjs"
"build:base": "nuxt build -c ./base/nuxt.config",
"build:replay": "nuxt build -c ./replay/nuxt.config",
"build:tracing": "nuxt build -c ./tracing/nuxt.config",
"build:lazy": "nuxt build -c ./lazy/nuxt.config",
"build:lazy+tracing": "nuxt build -c ./lazy+tracing/nuxt.config",
"build:typescript": "nuxt build -c ./typescript/nuxt.config"
}
}
21 changes: 21 additions & 0 deletions size-check/replay/nuxt.config.cjs
@@ -0,0 +1,21 @@
const SentryModule = require('../..')

/** @type {import('@nuxt/types').NuxtConfig} */
const config = {
rootDir: __dirname,
telemetry: false,
modules: [
/** @type {import('@nuxt/types').Module} */(/** @type {unknown} */(SentryModule)),
],
sentry: {
dsn: 'https://fe8b7df6ea7042f69d7a97c66c2934f7@sentry.io.nuxt/1429779',
clientIntegrations: {
// Integration from @Sentry/browser package.
TryCatch: { eventTarget: false },
Replay: {},
},

},
}

module.exports = config
36 changes: 36 additions & 0 deletions size-check/replay/pages/index.vue
@@ -0,0 +1,36 @@
<template>
<div>
<h3>Server-side</h3>
<span id="server-side">{{ serverSentryPresent ? 'Works!' : '$sentry object is missing!' }}</span>
<h3>Client-side</h3>
<span id="client-side">{{ clientSentryPresent ? 'Works!' : '$sentry object is missing!' }}</span>
<p>
<button id="crash-button" @click="crash_me()">
crash me
</button>
</p>
</div>
</template>

<script>
export default {
asyncData ({ $sentry }) {
if (process.server) {
return {
serverSentryPresent: Boolean($sentry?.captureException),
}
}
},
data () {
return {
clientSentryPresent: false,
serverSentryPresent: false,
}
},
created () {
if (process.client) {
this.clientSentryPresent = Boolean(this.$sentry?.captureException)
}
},
}
</script>
12 changes: 12 additions & 0 deletions size-check/typescript/config/server.config.ts
@@ -0,0 +1,12 @@
import { ModuleOptions } from 'src/types'

export default function (): ModuleOptions['serverConfig'] {
return {
beforeSend (event, _hint) {
event.extra = {
foo: '1',
}
return event
},
}
}
24 changes: 24 additions & 0 deletions size-check/typescript/nuxt.config.ts
@@ -0,0 +1,24 @@
import { fileURLToPath } from 'node:url'
import initJiti from 'jiti'
import type { NuxtConfig } from '@nuxt/types'

const jiti = initJiti(fileURLToPath(import.meta.url))

const config: NuxtConfig = {
rootDir: __dirname,
telemetry: false,
buildModules: [
'@nuxt/typescript-build',
],
modules: [
jiti.resolve('../..'),
],
sentry: {
dsn: 'https://fe8b7df6ea7042f69d7a97c66c2934f7@sentry.io.nuxt/1429779',
},
typescript: {
typeCheck: false,
},
}

export default config
44 changes: 44 additions & 0 deletions size-check/typescript/pages/index.vue
@@ -0,0 +1,44 @@
<template>
<div>
<h3>Server-side</h3>
<span id="server-side">{{ serverSentryPresent ? 'Works!' : '$sentry object is missing!' }}</span>
<h3>Client-side</h3>
<span id="client-side">{{ clientSentryPresent ? 'Works!' : '$sentry object is missing!' }}</span>
<p>
<button id="crash-button" @click="crash_me()">
crash me
</button>
</p>
</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
asyncData ({ $sentry, query }) {
if (query.crashOnLoad) {
// @ts-ignore forces a crash
// eslint-disable-next-line no-undef
crashOnLoad()
}
if (process.server) {
return {
serverSentryPresent: Boolean($sentry?.captureException),
}
}
},
data () {
return {
clientSentryPresent: false,
serverSentryPresent: false,
}
},
created () {
if (process.client) {
this.clientSentryPresent = Boolean(this.$sentry?.captureException)
}
},
})
</script>
8 changes: 8 additions & 0 deletions size-check/typescript/tsconfig.json
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"types": [
"@nuxt/typescript-build",
]
},
}
2 changes: 1 addition & 1 deletion src/module.ts
@@ -1,4 +1,4 @@
import { fileURLToPath } from 'url'
import { fileURLToPath } from 'node:url'
import { defu } from 'defu'
import { resolvePath } from 'mlly'
import type { SentryWebpackPluginOptions } from '@sentry/webpack-plugin'
Expand Down
10 changes: 8 additions & 2 deletions src/options.ts
@@ -1,5 +1,7 @@
import { fileURLToPath } from 'node:url'
import type { ConsolaInstance } from 'consola'
import { defu } from 'defu'
import initJiti from 'jiti'
import { relative } from 'pathe'
import { Integrations as ServerIntegrations, autoDiscoverNodePerformanceMonitoringIntegrations } from '@sentry/node'
import type Sentry from '@sentry/node'
Expand All @@ -11,6 +13,8 @@ import type { ModuleConfiguration } from './types'
import { Nuxt, resolveAlias } from './kit-shim'
import { canInitialize } from './utils'

const jiti = initJiti(fileURLToPath(import.meta.url))

export interface SentryHandlerProxy {
errorHandler: ReturnType<typeof Sentry.Handlers.errorHandler>
requestHandler: ReturnType<typeof Sentry.Handlers.requestHandler>
Expand Down Expand Up @@ -242,7 +246,8 @@ export async function resolveServerOptions (nuxt: Nuxt, moduleOptions: Readonly<
if (typeof (options.serverConfig) === 'string') {
const resolvedPath = resolveAlias(options.serverConfig)
try {
options.serverConfig = (await import(resolvedPath).then(m => m.default || m))()
const mod = jiti(resolvedPath)
options.serverConfig = (mod.default || mod)()
} catch (error) {
logger.error(`Error handling the serverConfig plugin:\n${error}`)
}
Expand All @@ -261,7 +266,8 @@ export async function resolveServerOptions (nuxt: Nuxt, moduleOptions: Readonly<
if (options.customServerIntegrations) {
const resolvedPath = resolveAlias(options.customServerIntegrations)
try {
customIntegrations = (await import(resolvedPath).then(m => m.default || m))()
const mod = jiti(resolvedPath)
customIntegrations = (mod.default || mod)()
if (!Array.isArray(customIntegrations)) {
logger.error(`Invalid value returned from customServerIntegrations plugin. Expected an array, got "${typeof (customIntegrations)}".`)
}
Expand Down
24 changes: 23 additions & 1 deletion test/default.test.ts
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { fileURLToPath } from 'url'
import { dirname } from 'path'
import { describe, afterAll, beforeAll, beforeEach, test, expect } from 'vitest'
Expand All @@ -20,7 +21,7 @@ describe('Smoke test (default)', () => {
beforeAll(async () => {
await localServer.start(TEST_DSN)
const dsn = localServer.getDsn()
nuxt = (await setup(await loadConfig(__dirname, 'default', { sentry: { dsn } }, { merge: true }))).nuxt
nuxt = (await setup(loadConfig(__dirname, 'default', { sentry: { dsn } }, { merge: true }))).nuxt
browser = await createBrowser()
})

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

test('catches a server crash', async () => {
const page = await browser.newPage()
const response = await page.goto(url('/?crashOnLoad=1'))
expect(response!.status()).toBe(500)

const reports = testkit.reports()
expect(reports).toHaveLength(1)
expect(reports[0].error?.message).toContain('crashOnLoad is not defined')
})

test('catches a client crash', async () => {
const page = await browser.newPage()
await page.goto(url('/'))

expect(await $$('#client-side', page)).toBe('Works!')
await page.click('#crash-button')
const reports = testkit.reports()
expect(reports).toHaveLength(1)
expect(reports[0].error?.message).toContain('crash_me is not a function')
})

// TODO: Add tests for custom integration. Blocked by various sentry-kit bugs reported in its repo.
})
8 changes: 7 additions & 1 deletion test/fixture/default/pages/index.vue
Expand Up @@ -14,7 +14,13 @@

<script>
export default {
asyncData ({ $sentry }) {
asyncData ({ $sentry, query }) {
if (query.crashOnLoad) {
// @ts-ignore forces a crash
// eslint-disable-next-line no-undef
crashOnLoad()
}
if (process.server) {
return {
serverSentryPresent: Boolean($sentry?.captureException),
Expand Down
6 changes: 6 additions & 0 deletions test/fixture/typescript/config/custom-client-integrations.ts
@@ -0,0 +1,6 @@
import type { Context } from '@nuxt/types'
import type { ModuleOptions } from 'src/types'

export default function (_context: Context): ModuleOptions['clientIntegrations'] {
return {}
}
12 changes: 12 additions & 0 deletions test/fixture/typescript/config/server.config.ts
@@ -0,0 +1,12 @@
import { ModuleOptions } from 'src/types'

export default function (): ModuleOptions['serverConfig'] {
return {
beforeSend (event, _hint) {
event.extra = {
foo: '1',
}
return event
},
}
}
46 changes: 46 additions & 0 deletions test/fixture/typescript/nuxt.config.ts
@@ -0,0 +1,46 @@
import { fileURLToPath } from 'node:url'
import initJiti from 'jiti'
import type { NuxtConfig } from '@nuxt/types'

const jiti = initJiti(fileURLToPath(import.meta.url))

const config: NuxtConfig = {
rootDir: __dirname,
telemetry: false,
build: {
terser: false,
},
render: {
resourceHints: false,
},
buildModules: [
'@nuxt/typescript-build',
],
modules: [
jiti.resolve('../../..'),
],
sentry: {
dsn: 'https://fe8b7df6ea7042f69d7a97c66c2934f7@sentry.io.nuxt/1429779',
clientIntegrations: {
// Integration from @Sentry/browser package.
TryCatch: { eventTarget: false },
Replay: {},
},
clientConfig: {
// This sets the sample rate to be 10%. You may want this to be 100% while
// in development and sample at a lower rate in production
replaysSessionSampleRate: 0.1,
// If the entire session is not sampled, use the below sample rate to sample
// sessions when an error occurs.
replaysOnErrorSampleRate: 1.0,
},
customClientIntegrations: '~/config/custom-client-integrations.ts',
serverConfig: '~/config/server.config',
tracing: true,
},
typescript: {
typeCheck: false,
},
}

export default config

0 comments on commit e481548

Please sign in to comment.