diff --git a/docs/platforms/javascript/guides/nextjs/manual-setup.mdx b/docs/platforms/javascript/guides/nextjs/manual-setup.mdx index b83a6d23d19a3a..8dd7cfdff736af 100644 --- a/docs/platforms/javascript/guides/nextjs/manual-setup.mdx +++ b/docs/platforms/javascript/guides/nextjs/manual-setup.mdx @@ -16,7 +16,13 @@ description: "Learn how to manually set up Sentry in your Next.js app and captur Choose the features you want to configure, and this guide will show you how: @@ -90,6 +96,7 @@ export default withSentryConfig(nextConfig, { ### Initialize Sentry Client-Side and Server-Side SDKs Create three files in your application's root directory: + - `sentry.server.config.(js|ts)` - `sentry.edge.config.(js|ts)` - `instrumentation-client.(js|ts)` @@ -220,7 +227,8 @@ Sentry.init({ ``` - Include your DSN directly in these files, or use a _public_ environment variable like `NEXT_PUBLIC_SENTRY_DSN`. + Include your DSN directly in these files, or use a _public_ environment + variable like `NEXT_PUBLIC_SENTRY_DSN`. ### Register Sentry Server-Side SDK Initialization @@ -433,7 +441,7 @@ module.exports = withSentryConfig(nextConfig, { }); ``` -Alternatively, set the `SENTRY_AUTH_TOKEN` environment variable in your `.env` file: +Set the `SENTRY_AUTH_TOKEN` environment variable in your `.env` file: ```sh {filename:.env} SENTRY_AUTH_TOKEN=___ORG_AUTH_TOKEN___ diff --git a/docs/platforms/javascript/guides/nuxt/manual-setup.mdx b/docs/platforms/javascript/guides/nuxt/manual-setup.mdx index 5cfb6a66c6e7b4..87ded1bb7689c9 100644 --- a/docs/platforms/javascript/guides/nuxt/manual-setup.mdx +++ b/docs/platforms/javascript/guides/nuxt/manual-setup.mdx @@ -51,7 +51,13 @@ Add the following overrides: Choose the features you want to configure, and this guide will show you how: @@ -218,20 +224,29 @@ Check out the `--import` CLI flagThese `sentry` options only affect the **build time** of the SDK. + +```javascript {filename:nuxt.config.ts} {3-10} export default defineNuxtConfig({ modules: ["@sentry/nuxt/module"], sentry: { sourceMapsUploadOptions: { org: "___ORG_SLUG___", project: "___PROJECT_SLUG___", - authToken: "___ORG_AUTH_TOKEN___", + // store your auth token in an environment variable + authToken: process.env.SENTRY_AUTH_TOKEN, }, }, }); ``` -These `sentry` options only affect the **build time** of the SDK. +To keep your auth token secure, always store it in an environment variable instead of directly in your files: + + + +```bash {filename:.env} +SENTRY_AUTH_TOKEN=___ORG_AUTH_TOKEN___ +``` While Nuxt generates source maps on the server side by default, you need to explicitly enable client-side source maps in your Nuxt configuration: diff --git a/docs/platforms/javascript/guides/react-router/index.mdx b/docs/platforms/javascript/guides/react-router/index.mdx index 326fa986efc7d8..c6454579c01235 100644 --- a/docs/platforms/javascript/guides/react-router/index.mdx +++ b/docs/platforms/javascript/guides/react-router/index.mdx @@ -9,7 +9,7 @@ categories: - server-node --- - + This SDK is currently in **beta**. Beta features are still in progress and may have bugs. Please reach out on [GitHub](https://github.com/getsentry/sentry-javascript/issues/new/choose) if @@ -18,7 +18,7 @@ categories: - If you are using React Router in library mode, you can follow the instructions in the [React guide here](/platforms/javascript/guides/react/features/react-router/v7). +If you are using React Router in library mode, you can follow the instructions in the [React guide here](/platforms/javascript/guides/react/features/react-router/v7). @@ -36,25 +36,25 @@ Sentry captures data by using an SDK within your application's runtime. "user-feedback", "logs", { - id: 'profiling', - checked: false - } + id: "profiling", + checked: false, + }, ]} /> - ```bash {tabTitle:npm} - npm install @sentry/react-router @sentry/profiling-node - ``` +```bash {tabTitle:npm} +npm install @sentry/react-router @sentry/profiling-node +``` - ```bash {tabTitle:yarn} - yarn add @sentry/react-router @sentry/profiling-node - ``` +```bash {tabTitle:yarn} +yarn add @sentry/react-router @sentry/profiling-node +``` - ```bash {tabTitle:pnpm} - pnpm add @sentry/react-router @sentry/profiling-node - ``` +```bash {tabTitle:pnpm} +pnpm add @sentry/react-router @sentry/profiling-node +``` @@ -63,18 +63,20 @@ Sentry captures data by using an SDK within your application's runtime. npm install @sentry/react-router ``` - ```bash {tabTitle:yarn} - yarn add @sentry/react-router - ``` +```bash {tabTitle:yarn} +yarn add @sentry/react-router +``` + +```bash {tabTitle:pnpm} +pnpm add @sentry/react-router +``` - ```bash {tabTitle:pnpm} - pnpm add @sentry/react-router - ``` ## Configure ### Expose Hooks + React Router exposes two hooks in your `app` folder (`entry.client.tsx` and `entry.server.tsx`). If you do not see these two files, expose them with the following command: @@ -94,11 +96,11 @@ Initialize the Sentry React SDK in your `entry.client.tsx` file: +Sentry.init({ + dsn: "___PUBLIC_DSN___", -+ ++ + // Adds request headers and IP for users, for more info visit: + // https://docs.sentry.io/platforms/javascript/guides/react-router/configuration/options/#sendDefaultPii + sendDefaultPii: true, -+ ++ + integrations: [ + // ___PRODUCT_OPTION_START___ performance + Sentry.reactRouterTracingIntegration(), @@ -190,38 +192,41 @@ export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) { Automatic server-side instrumentation is currently only supported on: - **Node 20:** Version \<20.19 - **Node 22:** Version \<22.12 - - - If you are on a different version please make use of our manual server wrappers. - - For server loaders use `wrapServerLoader`: + +If you are on a different version please make use of our manual server wrappers. + +For server loaders use `wrapServerLoader`: + ```ts -import * as Sentry from '@sentry/react-router'; +import * as Sentry from "@sentry/react-router"; export const loader = Sentry.wrapServerLoader( { - name: 'Load Some Data', - description: 'Loads some data from the db', + name: "Load Some Data", + description: "Loads some data from the db", }, async ({ params }) => { // ... your loader logic } ); ``` - For server actions use `wrapServerAction`: + +For server actions use `wrapServerAction`: + ```ts -import * as Sentry from '@sentry/react-router'; +import * as Sentry from "@sentry/react-router"; export const action = Sentry.wrapServerAction( { - name: 'Submit Form Data', - description: 'Processes form submission data', + name: "Submit Form Data", + description: "Processes form submission data", }, async ({ request }) => { // ... your action logic } ); ``` + Create an `instrument.server.mjs` file in the root of your app: @@ -229,12 +234,12 @@ Create an `instrument.server.mjs` file in the root of your app: ```js {filename: instrument.server.mjs} import * as Sentry from "@sentry/react-router"; // ___PRODUCT_OPTION_START___ profiling -import { nodeProfilingIntegration } from '@sentry/profiling-node'; +import { nodeProfilingIntegration } from "@sentry/profiling-node"; // ___PRODUCT_OPTION_END___ profiling Sentry.init({ dsn: "___PUBLIC_DSN___", - + // Adds request headers and IP for users, for more info visit: // https://docs.sentry.io/platforms/javascript/guides/react-router/configuration/options/#sendDefaultPii sendDefaultPii: true, @@ -244,7 +249,7 @@ Sentry.init({ _experiments: { enableLogs: true }, // ___PRODUCT_OPTION_END___ logs // ___PRODUCT_OPTION_START___ profiling - + integrations: [nodeProfilingIntegration()], // ___PRODUCT_OPTION_END___ profiling // ___PRODUCT_OPTION_START___ performance @@ -288,76 +293,80 @@ export const handleError: HandleErrorFunction = (error, { request }) => { If you need to update the logic of your `handleRequest` function you'll need to include the provided Sentry helper functions (`getMetaTagTransformer` and `wrapSentryHandleRequest`) manually: - - ```tsx {1-4, 44-45, 69-70} - import { getMetaTagTransformer, wrapSentryHandleRequest } from '@sentry/react-router'; - // ... other imports - - const handleRequest = function handleRequest( - request: Request, - responseStatusCode: number, - responseHeaders: Headers, - routerContext: EntryContext, - _loadContext: AppLoadContext, - ): Promise { - return new Promise((resolve, reject) => { - let shellRendered = false; - const userAgent = request.headers.get('user-agent'); - - // Determine if we should use onAllReady or onShellReady - const isBot = typeof userAgent === 'string' && botRegex.test(userAgent); - const isSpaMode = !!(routerContext as { isSpaMode?: boolean }).isSpaMode; - - const readyOption = isBot || isSpaMode ? 'onAllReady' : 'onShellReady'; - - const { pipe, abort } = renderToPipeableStream( - , - { - [readyOption]() { - shellRendered = true; - const body = new PassThrough(); - - const stream = createReadableStreamFromReadable(body); - - responseHeaders.set('Content-Type', 'text/html'); - - resolve( - new Response(stream, { - headers: responseHeaders, - status: responseStatusCode, - }), - ); - - // this enables distributed tracing between client and server - pipe(getMetaTagTransformer(body)); - }, - onShellError(error: unknown) { - reject(error); - }, - onError(error: unknown) { - // eslint-disable-next-line no-param-reassign - responseStatusCode = 500; - // Log streaming rendering errors from inside the shell. Don't log - // errors encountered during initial shell rendering since they'll - // reject and get logged in handleDocumentRequest. - if (shellRendered) { - // eslint-disable-next-line no-console - console.error(error); - } - }, + +```tsx {1-4, 44-45, 69-70} +import { + getMetaTagTransformer, + wrapSentryHandleRequest, +} from "@sentry/react-router"; +// ... other imports + +const handleRequest = function handleRequest( + request: Request, + responseStatusCode: number, + responseHeaders: Headers, + routerContext: EntryContext, + _loadContext: AppLoadContext +): Promise { + return new Promise((resolve, reject) => { + let shellRendered = false; + const userAgent = request.headers.get("user-agent"); + + // Determine if we should use onAllReady or onShellReady + const isBot = typeof userAgent === "string" && botRegex.test(userAgent); + const isSpaMode = !!(routerContext as { isSpaMode?: boolean }).isSpaMode; + + const readyOption = isBot || isSpaMode ? "onAllReady" : "onShellReady"; + + const { pipe, abort } = renderToPipeableStream( + , + { + [readyOption]() { + shellRendered = true; + const body = new PassThrough(); + + const stream = createReadableStreamFromReadable(body); + + responseHeaders.set("Content-Type", "text/html"); + + resolve( + new Response(stream, { + headers: responseHeaders, + status: responseStatusCode, + }) + ); + + // this enables distributed tracing between client and server + pipe(getMetaTagTransformer(body)); + }, + onShellError(error: unknown) { + reject(error); + }, + onError(error: unknown) { + // eslint-disable-next-line no-param-reassign + responseStatusCode = 500; + // Log streaming rendering errors from inside the shell. Don't log + // errors encountered during initial shell rendering since they'll + // reject and get logged in handleDocumentRequest. + if (shellRendered) { + // eslint-disable-next-line no-console + console.error(error); + } }, - ); + } + ); - // Abort the rendering stream after the `streamTimeout` - setTimeout(abort, streamTimeout); - }); - }; - - // wrap the default export - export default wrapSentryHandleRequest(handleRequest); + // Abort the rendering stream after the `streamTimeout` + setTimeout(abort, streamTimeout); + }); +}; + +// wrap the default export +export default wrapSentryHandleRequest(handleRequest); + +// ... rest of your entry.server.ts file +``` - // ... rest of your entry.server.ts file - ``` ### Update Scripts @@ -369,8 +378,8 @@ Update the `start` and `dev` script to include the instrumentation file: ```json {filename: package.json} "scripts": { - "dev": "NODE_OPTIONS='--import ./instrument.server.mjs' react-router dev", - "start": "NODE_OPTIONS='--import ./instrument.server.mjs' react-router-serve ./build/server/index.js", +"dev": "NODE_OPTIONS='--import ./instrument.server.mjs' react-router dev", +"start": "NODE_OPTIONS='--import ./instrument.server.mjs' react-router-serve ./build/server/index.js", } ``` @@ -388,7 +397,7 @@ If you're deploying to platforms like **Vercel** or **Netlify** where setting th - When importing the instrumentation file directly in `entry.server.tsx` instead of using the `--import` flag, automatic instrumentation will be incomplete and you'll miss automatically captured spans and traces for some of your application's server-side operations. This approach should only be used when the `NODE_OPTIONS` approach is not available on your hosting platform. +When importing the instrumentation file directly in `entry.server.tsx` instead of using the `--import` flag, automatic instrumentation will be incomplete and you'll miss automatically captured spans and traces for some of your application's server-side operations. This approach should only be used when the `NODE_OPTIONS` approach is not available on your hosting platform. @@ -396,8 +405,6 @@ If you're deploying to platforms like **Vercel** or **Netlify** where setting th Update `vite.config.ts` to include the `sentryReactRouter` plugin, making sure to pass both the Vite and Sentry configurations to it: - - ```typescript {filename: vite.config.ts} {diff} import { reactRouter } from '@react-router/dev/vite'; import { sentryReactRouter, type SentryReactRouterBuildOptions } from '@sentry/react-router'; @@ -407,8 +414,9 @@ const sentryConfig: SentryReactRouterBuildOptions = { org: "___ORG_SLUG___", project: "___PROJECT_SLUG___", - // An auth token is required for uploading source maps. - authToken: "___ORG_AUTH_TOKEN___" + // An auth token is required for uploading source maps; + // store it in an environment variable to keep it secure. + authToken: process.env.SENTRY_AUTH_TOKEN, // ... }; @@ -419,18 +427,26 @@ export default defineConfig(config => { }); ``` +To keep your auth token secure, always store it in an environment variable instead of directly in your files: + + + +```bash {filename:.env} +SENTRY_AUTH_TOKEN=___ORG_AUTH_TOKEN___ +``` + Include the `sentryOnBuildEnd` hook in `react-router.config.ts`: ```typescript {filename: react-router.config.ts} {diff} -import type { Config } from '@react-router/dev/config'; -import { sentryOnBuildEnd } from '@sentry/react-router'; +import type { Config } from "@react-router/dev/config"; +import { sentryOnBuildEnd } from "@sentry/react-router"; export default { ssr: true, buildEnd: async ({ viteConfig, reactRouterConfig, buildManifest }) => { // ... // Call this at the end of the hook -+ await sentryOnBuildEnd({ viteConfig, reactRouterConfig, buildManifest }); ++ (await sentryOnBuildEnd({ viteConfig, reactRouterConfig, buildManifest })); }, } satisfies Config; ``` @@ -450,13 +466,8 @@ export async function loader() { } export default function ExamplePage() { - return ( -
- Loading this page will throw an error -
- ); + return
Loading this page will throw an error
; } - ``` diff --git a/docs/platforms/javascript/guides/solidstart/index.mdx b/docs/platforms/javascript/guides/solidstart/index.mdx index e97050c79dddc0..b37eaf99f4b0cf 100644 --- a/docs/platforms/javascript/guides/solidstart/index.mdx +++ b/docs/platforms/javascript/guides/solidstart/index.mdx @@ -9,7 +9,7 @@ categories: ## Install -Sentry captures data by using an SDK within your application’s runtime. +Sentry captures data by using an SDK within your application's runtime. ```bash {tabTitle:npm} npm install @sentry/solidstart --save @@ -31,30 +31,29 @@ Initialize the Sentry SDK in your `src/entry-client.tsx` file. If you're using Solid Router, add the `solidRouterBrowserTracingIntegration` to collect meaningful performance data about the health of your page loads and associated requests. - ```jsx {filename:src/entry-client.tsx} -import * as Sentry from '@sentry/solidstart'; -import { solidRouterBrowserTracingIntegration } from '@sentry/solidstart/solidrouter'; -import { mount, StartClient } from '@solidjs/start/client'; +import * as Sentry from "@sentry/solidstart"; +import { solidRouterBrowserTracingIntegration } from "@sentry/solidstart/solidrouter"; +import { mount, StartClient } from "@solidjs/start/client"; Sentry.init({ - dsn: '___PUBLIC_DSN___', - + dsn: "___PUBLIC_DSN___", + // Adds request headers and IP for users, for more info visit: // https://docs.sentry.io/platforms/javascript/guides/solidstart/configuration/options/#sendDefaultPii sendDefaultPii: true, - + integrations: [solidRouterBrowserTracingIntegration()], tracesSampleRate: 1.0, // Capture 100% of the transactions }); -mount(() => , document.getElementById('app')); +mount(() => , document.getElementById("app")); ``` - Depending on the configuration of your SolidStart project, the file structure may differ from the code listed on this page. - For example, for JavaScript projects files end in `.js` and `.jsx` while we use TypeScript snippets here ending in `.ts` and `.tsx`. +Depending on the configuration of your SolidStart project, the file structure may differ from the code listed on this page. +For example, for JavaScript projects files end in `.js` and `.jsx` while we use TypeScript snippets here ending in `.ts` and `.tsx`. @@ -63,15 +62,15 @@ mount(() => , document.getElementById('app')); Create an instrument file `instrument.server.ts` in your `src` folder. In this file, initialize the Sentry SDK for your server. ```javascript {filename:src/instrument.server.ts} -import * as Sentry from '@sentry/solidstart'; +import * as Sentry from "@sentry/solidstart"; Sentry.init({ - dsn: '___PUBLIC_DSN___', - + dsn: "___PUBLIC_DSN___", + // Adds request headers and IP for users, for more info visit: // https://docs.sentry.io/platforms/javascript/guides/solidstart/configuration/options/#sendDefaultPii sendDefaultPii: true, - + tracesSampleRate: 1.0, // Capture 100% of the transactions }); ``` @@ -79,8 +78,8 @@ Sentry.init({ Wrap your SolidStart config with `withSentry`, so this file gets added to your build output. With the default server preset, you can find the file here: `.output/server/instrument.server.mjs`. ```javascript {filename:app.config.ts} {5-12} -import { withSentry } from '@sentry/solidstart'; -import { defineConfig } from '@solidjs/start/config'; +import { withSentry } from "@sentry/solidstart"; +import { defineConfig } from "@solidjs/start/config"; export default defineConfig( withSentry( @@ -90,7 +89,7 @@ export default defineConfig( { /* Your Sentry build-time config (such as source map upload options) */ } - ), + ) ); ``` @@ -101,8 +100,8 @@ The Sentry SDK provides [middleware lifecycle](https://docs.solidjs.com/solid-st Complete the setup by adding `sentryBeforeResponseMiddleware` to your `src/middleware.ts` file. If you don't have a `src/middleware.ts` file yet, create one: ```typescript {filename:src/middleware.ts} {6} -import { sentryBeforeResponseMiddleware } from '@sentry/solidstart'; -import { createMiddleware } from '@solidjs/start/middleware'; +import { sentryBeforeResponseMiddleware } from "@sentry/solidstart"; +import { createMiddleware } from "@solidjs/start/middleware"; export default createMiddleware({ onBeforeResponse: [ @@ -115,13 +114,13 @@ export default createMiddleware({ And specify `src/middleware.ts` in `app.config.ts`: ```typescript {filename:app.config.ts} {7} -import { withSentry } from '@sentry/solidstart'; -import { defineConfig } from '@solidjs/start/config'; +import { withSentry } from "@sentry/solidstart"; +import { defineConfig } from "@solidjs/start/config"; export default defineConfig( withSentry({ // other SolidStart config options... - middleware: './src/middleware.ts', + middleware: "./src/middleware.ts", }) ); ``` @@ -132,9 +131,9 @@ This creates a higher order component, which will enable Sentry to collect navig ```tsx {filename:app.tsx} {5,9,11} import { Router } from "@solidjs/router"; import { FileRoutes } from "@solidjs/start/router"; -import { withSentryRouterRouting } from '@sentry/solidstart/solidrouter' +import { withSentryRouterRouting } from "@sentry/solidstart/solidrouter"; -const SentryRouter = withSentryRouterRouting(Router) +const SentryRouter = withSentryRouterRouting(Router); export default function App() { return ( @@ -161,18 +160,18 @@ For example, update your scripts in `package.json`. ``` - If you experience any issues during the server-side setup, read through the different installation methods - or check out Troubleshooting. + If you experience any issues during the server-side setup, read through the + different installation methods + or check out{" "} + Troubleshooting. ## Add Readable Stack Traces to Errors -To upload source maps, configure an auth token. Auth tokens can be passed to `withSentry` explicitly with the `authToken` -option. You can also use the `SENTRY_AUTH_TOKEN` environment variable or have an `.env.sentry-build-plugin` file in the +To upload source maps, you need to pass an auth token to `withSentry` explicitly with the `authToken` +option. We highly recommend to store this token in an environment variable for security. You can also use the `SENTRY_AUTH_TOKEN` environment variable or have an `.env.sentry-build-plugin` file in the working directory when building your project. - - Update your `app.config.ts`: ```TypeScript {filename:app.config.ts} @@ -187,12 +186,21 @@ export default defineConfig( { org: "___ORG_SLUG___", project: "___PROJECT_SLUG___", - authToken: "___ORG_AUTH_TOKEN___", + // store your auth token in an environment variable + authToken: process.env.SENTRY_AUTH_TOKEN, } ), ); ``` +Store your token in an environment variable: + + + +```bash {filename:.env} +SENTRY_AUTH_TOKEN=___ORG_AUTH_TOKEN___ +``` + or create a `.env.sentry-build-plugin` file: ```bash {filename:.env.sentry-build-plugin}