From 709592f9653605b8f68dac9485c651b7bc592c72 Mon Sep 17 00:00:00 2001 From: s1gr1d Date: Tue, 10 Sep 2024 11:26:43 +0200 Subject: [PATCH 1/5] feat(nuxt): Adding `simplifiedDeployment` option to Nuxt module --- packages/nuxt/src/common/types.ts | 10 ++++++ packages/nuxt/src/module.ts | 21 +++++++----- packages/nuxt/src/vite/addServerConfig.ts | 41 +++++++++++++++++++++-- 3 files changed, 61 insertions(+), 11 deletions(-) diff --git a/packages/nuxt/src/common/types.ts b/packages/nuxt/src/common/types.ts index 08dc0d2b805e..314d27029269 100644 --- a/packages/nuxt/src/common/types.ts +++ b/packages/nuxt/src/common/types.ts @@ -99,4 +99,14 @@ export type SentryNuxtModuleOptions = { * Enabling this will give you, for example, logs about source maps. */ debug?: boolean; + + /** + * Enabling simplified deployment can be used for environments where modifying the node option `--import` is not possible. + * If this flag is `true`, the Sentry SDK will import the server config at the top of the server entry file to load the SDK on the server. + * + * Note that enabling this option only supports limited tracing instrumentation. Only http traces will be collected. + * + * @default false + */ + simplifiedDeployment?: boolean; }; diff --git a/packages/nuxt/src/module.ts b/packages/nuxt/src/module.ts index faa48e5c3c26..453a4941dc99 100644 --- a/packages/nuxt/src/module.ts +++ b/packages/nuxt/src/module.ts @@ -1,6 +1,6 @@ import { addPlugin, addPluginTemplate, addServerPlugin, createResolver, defineNuxtModule } from '@nuxt/kit'; import type { SentryNuxtModuleOptions } from './common/types'; -import { addServerConfigToBuild } from './vite/addServerConfig'; +import { addSentryTopImport, addServerConfigToBuild } from './vite/addServerConfig'; import { setupSourceMaps } from './vite/sourceMaps'; import { findDefaultSdkInitFile } from './vite/utils'; @@ -62,15 +62,20 @@ export default defineNuxtModule({ if (clientConfigFile || serverConfigFile) { setupSourceMaps(moduleOptions, nuxt); } - if (serverConfigFile && serverConfigFile.includes('.server.config')) { - if (moduleOptions.debug) { - // eslint-disable-next-line no-console - console.log( - `[Sentry] Using your \`${serverConfigFile}\` file for the server-side Sentry configuration. In case you have a \`public/instrument.server\` file, the \`public/instrument.server\` file will be ignored. Make sure the file path in your node \`--import\` option matches the Sentry server config file in your \`.output\` folder and has a \`.mjs\` extension.`, - ); - } + if (serverConfigFile && serverConfigFile.includes('.server.config')) { addServerConfigToBuild(moduleOptions, nuxt, serverConfigFile); + + if (moduleOptions.simplifiedDeployment) { + addSentryTopImport(moduleOptions, nuxt); + } else { + if (moduleOptions.debug) { + // eslint-disable-next-line no-console + console.log( + `[Sentry] Using your \`${serverConfigFile}\` file for the server-side Sentry configuration. In case you have a \`public/instrument.server\` file, the \`public/instrument.server\` file will be ignored. Make sure the file path in your node \`--import\` option matches the Sentry server config file in your \`.output\` folder and has a \`.mjs\` extension.`, + ); + } + } } }, }); diff --git a/packages/nuxt/src/vite/addServerConfig.ts b/packages/nuxt/src/vite/addServerConfig.ts index dc1fc21dd6bd..dee15ee34dce 100644 --- a/packages/nuxt/src/vite/addServerConfig.ts +++ b/packages/nuxt/src/vite/addServerConfig.ts @@ -1,5 +1,4 @@ import * as fs from 'fs'; -import * as path from 'path'; import { createResolver } from '@nuxt/kit'; import type { Nuxt } from '@nuxt/schema'; import type { SentryNuxtModuleOptions } from '../common/types'; @@ -30,8 +29,9 @@ export function addServerConfigToBuild( * This is necessary because we need to reference this file path in the node --import option. */ nuxt.hook('close', async () => { - const source = path.resolve('.nuxt/dist/server/sentry.server.config.mjs'); - const destination = path.resolve('.output/server/sentry.server.config.mjs'); + const rootDirResolver = createResolver(nuxt.options.rootDir); + const source = rootDirResolver.resolve('.nuxt/dist/server/sentry.server.config.mjs'); + const destination = rootDirResolver.resolve('.output/server/sentry.server.config.mjs'); try { await fs.promises.access(source, fs.constants.F_OK); @@ -55,3 +55,38 @@ export function addServerConfigToBuild( }); }); } + +/** + * Adds the Sentry server config import at the top of the server entry file to load the SDK on the server. + * This is necessary for environments where modifying the node option `--import` is not possible. + * However, only limited tracing instrumentation is supported when doing this. + */ +export function addSentryTopImport(moduleOptions: SentryNuxtModuleOptions, nuxt: Nuxt): void { + nuxt.hook('close', async () => { + const rootDirResolver = createResolver(nuxt.options.rootDir); + const entryFilePath = rootDirResolver.resolve('.output/server/index.mjs'); + + try { + fs.readFile(entryFilePath, 'utf8', (err, data) => { + const updatedContent = `import './sentry.server.config.mjs';\n${data}`; + + fs.writeFile(entryFilePath, updatedContent, 'utf8', () => { + if (moduleOptions.debug) { + // eslint-disable-next-line no-console + console.log( + `[Sentry] Successfully added the Sentry import to the server entry file "\`${entryFilePath}\`"`, + ); + } + }); + }); + } catch (err) { + if (moduleOptions.debug) { + // eslint-disable-next-line no-console + console.warn( + `[Sentry] An error occurred when trying to add the Sentry import to the server entry file "\`${entryFilePath}\`":`, + err, + ); + } + } + }); +} From 14a94e4530acb1d436e114a9f7002a22a072406c Mon Sep 17 00:00:00 2001 From: s1gr1d Date: Tue, 10 Sep 2024 16:40:42 +0200 Subject: [PATCH 2/5] update readme with server setup --- packages/nuxt/README.md | 51 +++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/packages/nuxt/README.md b/packages/nuxt/README.md index df41599e45b9..e164a29e57a9 100644 --- a/packages/nuxt/README.md +++ b/packages/nuxt/README.md @@ -37,21 +37,20 @@ functionality related to Nuxt. **What is partly working:** +- Source Maps +- Connected Tracing (Frontend & Backend) - Tracing by setting `tracesSampleRate` - UI (Vue) traces - HTTP (Node) traces -**What is not yet(!) included:** - -- Source Maps -- Nuxt-specific traces and connecting frontend & backend traces - **Known Issues:** -- When adding `sentry.server.config.(ts/js)`, you get this error: "Failed to register ESM hook", but the application - will still work -- When initializing Sentry on the server with `instrument.server.(js|ts)`, you get an `'import-in-the-middle'` error, - and the application won't work +- When adding `sentry.server.config.(ts/js)`, you get an error like this: "`Failed to register ESM hook (import-in-the-middle/hook.mjs)`". You can add a resolution for `@vercel/nft` to fix this. This will add the `hook.mjs` file to your build output ([issue here](https://github.com/unjs/nitro/issues/2703)). + ```json + "resolutions": { + "@vercel/nft": "^0.27.4" + } + ``` ## Automatic Setup @@ -93,16 +92,18 @@ export default defineNuxtConfig({ Add a `sentry.client.config.(js|ts)` file to the root of your project: ```javascript +import { useRuntimeConfig } from "#imports"; import * as Sentry from '@sentry/nuxt'; Sentry.init({ - dsn: process.env.SENTRY_DSN, + // If set up, you can use your runtime config here + dsn: useRuntimeConfig().public.sentry.dsn, }); ``` ### 4. Server-side setup -Add an `instrument.server.mjs` file to your `public` folder: +Add an `sentry.client.config.(js|ts)` file to the root of your project: ```javascript import * as Sentry from '@sentry/nuxt'; @@ -110,18 +111,38 @@ import * as Sentry from '@sentry/nuxt'; // Only run `init` when process.env.SENTRY_DSN is available. if (process.env.SENTRY_DSN) { Sentry.init({ - dsn: process.env.SENTRY_DSN, + dsn: "your-dsn", }); } ``` -Add an import flag to the `NODE_OPTIONS` of your preview script in the `package.json` file, so the file loads before any -other imports: +The Nuxt runtime config does not work in the Sentry server to technical reasons (it has to be loaded before Nuxt is loaded). +To be able to use `process.env` you either have to add `--env-file=.env` to your node command + +```bash +node --env-file=.env --import ./.output/server/sentry.server.config.mjs .output/server/index.mjs +``` + +or use the `dotenv` package: + +```javascript +import dotenv from "dotenv"; +import * as Sentry from '@sentry/nuxt'; + +dotenv.config(); + +Sentry.init({ + dsn: process.env.SENTRY_DSN, +}); +``` + +Add an import flag to the Node options of your `node` command (not `nuxt preview`), so the file loads before any +other imports (keep in mind the `.mjs` file ending): ```json { "scripts": { - "preview": "NODE_OPTIONS='--import ./public/instrument.server.mjs' nuxt preview" + "start": "node --import ./.output/server/sentry.server.config.mjs .output/server/index.mjs" } } ``` From 8bd51f42b234b2f54016cf83a60c1ea694fb071f Mon Sep 17 00:00:00 2001 From: s1gr1d Date: Tue, 10 Sep 2024 17:17:27 +0200 Subject: [PATCH 3/5] change option naming --- packages/nuxt/src/common/types.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/nuxt/src/common/types.ts b/packages/nuxt/src/common/types.ts index 314d27029269..5fbe68bd89cb 100644 --- a/packages/nuxt/src/common/types.ts +++ b/packages/nuxt/src/common/types.ts @@ -101,12 +101,14 @@ export type SentryNuxtModuleOptions = { debug?: boolean; /** - * Enabling simplified deployment can be used for environments where modifying the node option `--import` is not possible. - * If this flag is `true`, the Sentry SDK will import the server config at the top of the server entry file to load the SDK on the server. + * Enabling basic server tracing can be used for environments where modifying the node option `--import` is not possible. + * However, enabling this option only supports limited tracing instrumentation. Only http traces will be collected (but no database-specific traces etc.). * - * Note that enabling this option only supports limited tracing instrumentation. Only http traces will be collected. + * If this option is `true`, the Sentry SDK will import the Sentry server config at the top of the server entry file to load the SDK on the server. + * + * **DO NOT** enable this option if you've already added the node option `--import` in your node start script. This would initialize Sentry twice on the server-side and leads to unexpected issues. * * @default false */ - simplifiedDeployment?: boolean; + experimental_basicServerTracing?: boolean; }; From 5d80c8f5c585044c5d0381d1b8292fb738f4eb16 Mon Sep 17 00:00:00 2001 From: s1gr1d Date: Tue, 10 Sep 2024 17:19:57 +0200 Subject: [PATCH 4/5] change option naming --- packages/nuxt/src/module.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nuxt/src/module.ts b/packages/nuxt/src/module.ts index 453a4941dc99..0afdeaa03de7 100644 --- a/packages/nuxt/src/module.ts +++ b/packages/nuxt/src/module.ts @@ -66,7 +66,7 @@ export default defineNuxtModule({ if (serverConfigFile && serverConfigFile.includes('.server.config')) { addServerConfigToBuild(moduleOptions, nuxt, serverConfigFile); - if (moduleOptions.simplifiedDeployment) { + if (moduleOptions.experimental_basicServerTracing) { addSentryTopImport(moduleOptions, nuxt); } else { if (moduleOptions.debug) { From b9973306bfb91d4b2bad0c55359510d3b731257f Mon Sep 17 00:00:00 2001 From: s1gr1d Date: Thu, 12 Sep 2024 16:12:57 +0200 Subject: [PATCH 5/5] prettier fix --- packages/nuxt/README.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/nuxt/README.md b/packages/nuxt/README.md index e164a29e57a9..b16d555a3648 100644 --- a/packages/nuxt/README.md +++ b/packages/nuxt/README.md @@ -45,7 +45,10 @@ functionality related to Nuxt. **Known Issues:** -- When adding `sentry.server.config.(ts/js)`, you get an error like this: "`Failed to register ESM hook (import-in-the-middle/hook.mjs)`". You can add a resolution for `@vercel/nft` to fix this. This will add the `hook.mjs` file to your build output ([issue here](https://github.com/unjs/nitro/issues/2703)). +- When adding `sentry.server.config.(ts/js)`, you get an error like this: + "`Failed to register ESM hook (import-in-the-middle/hook.mjs)`". You can add a resolution for `@vercel/nft` to fix + this. This will add the `hook.mjs` file to your build output + ([issue here](https://github.com/unjs/nitro/issues/2703)). ```json "resolutions": { "@vercel/nft": "^0.27.4" @@ -92,7 +95,7 @@ export default defineNuxtConfig({ Add a `sentry.client.config.(js|ts)` file to the root of your project: ```javascript -import { useRuntimeConfig } from "#imports"; +import { useRuntimeConfig } from '#imports'; import * as Sentry from '@sentry/nuxt'; Sentry.init({ @@ -111,13 +114,13 @@ import * as Sentry from '@sentry/nuxt'; // Only run `init` when process.env.SENTRY_DSN is available. if (process.env.SENTRY_DSN) { Sentry.init({ - dsn: "your-dsn", + dsn: 'your-dsn', }); } ``` -The Nuxt runtime config does not work in the Sentry server to technical reasons (it has to be loaded before Nuxt is loaded). -To be able to use `process.env` you either have to add `--env-file=.env` to your node command +The Nuxt runtime config does not work in the Sentry server to technical reasons (it has to be loaded before Nuxt is +loaded). To be able to use `process.env` you either have to add `--env-file=.env` to your node command ```bash node --env-file=.env --import ./.output/server/sentry.server.config.mjs .output/server/index.mjs @@ -126,7 +129,7 @@ node --env-file=.env --import ./.output/server/sentry.server.config.mjs .output/ or use the `dotenv` package: ```javascript -import dotenv from "dotenv"; +import dotenv from 'dotenv'; import * as Sentry from '@sentry/nuxt'; dotenv.config(); @@ -136,8 +139,8 @@ Sentry.init({ }); ``` -Add an import flag to the Node options of your `node` command (not `nuxt preview`), so the file loads before any -other imports (keep in mind the `.mjs` file ending): +Add an import flag to the Node options of your `node` command (not `nuxt preview`), so the file loads before any other +imports (keep in mind the `.mjs` file ending): ```json {