Skip to content

Commit

Permalink
feat(nextjs): Remove client.(server|client).config.ts functionality…
Browse files Browse the repository at this point in the history
… in favor of `instrumentation.ts` (#11059)
  • Loading branch information
lforst committed Mar 18, 2024
1 parent ffdc8aa commit 093531e
Show file tree
Hide file tree
Showing 26 changed files with 287 additions and 327 deletions.
50 changes: 50 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,56 @@ setup for source maps in Sentry and will not require you to match stack frame pa
To see the new options, check out the docs at https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/,
or look at the TypeScript type definitions of `withSentryConfig`.

#### Updated the recommended way of calling `Sentry.init()`

With version 8 of the SDK we will no longer support the use of `sentry.server.config.ts` and `sentry.edge.config.ts`
files. Instead, please initialize the Sentry Next.js SDK for the serverside in a
[Next.js instrumentation hook](https://nextjs.org/docs/app/building-your-application/optimizing/instrumentation).
**`sentry.client.config.ts|js` is still supported and encouraged for initializing the clientside SDK.**

The following is an example of how to initialize the serverside SDK in a Next.js instrumentation hook:

1. First, enable the Next.js instrumentation hook by setting the `experimental.instrumentationHook` to `true` in your
`next.config.js`.
2. Next, create a `instrumentation.ts|js` file in the root directory of your project (or in the `src` folder if you have
have one).
3. Now, export a `register` function from the `instrumentation.ts|js` file and call `Sentry.init()` inside of it:

```ts
import * as Sentry from '@sentry/nextjs';

export function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
Sentry.init({
dsn: 'YOUR_DSN',
// Your Node.js Sentry configuration...
});
}

if (process.env.NEXT_RUNTIME === 'edge') {
Sentry.init({
dsn: 'YOUR_DSN',
// Your Edge Runtime Sentry configuration...
});
}
}
```

Note that you can initialize the SDK differently depending on which server runtime is being used.

If you are using a
[Next.js custom server](https://nextjs.org/docs/pages/building-your-application/configuring/custom-server), the
`instrumentation.ts` hook is not called by Next.js so you need to manually call it yourself from within your server
code. It is recommended to do so as early as possible in your application lifecycle.

**Why are we making this change?** The very simple reason is that Next.js requires us to set up OpenTelemetry
instrumentation inside the `register` function of the instrumentation hook. Looking a little bit further into the
future, we also would like the Sentry SDK to be compatible with [Turbopack](https://turbo.build/pack), which is gonna be
the bundler that Next.js will be using instead of Webpack. The SDK in its previous version depended heavily on Webpack
in order to inject the `sentry.(server|edge).config.ts` files into the server-side code. Because this will not be
possible in the future, we are doing ourselves a favor and doing things the way Next.js intends us to do them -
hopefully reducing bugs and jank.

### Astro SDK

#### Removal of `trackHeaders` option for Astro middleware
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as Sentry from '@sentry/nextjs';

declare global {
namespace globalThis {
var transactionIds: string[];
}
}

export function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
Sentry.init({
environment: 'qa', // dynamic sampling bias to keep transactions
dsn: process.env.NEXT_PUBLIC_E2E_TEST_DSN,
// Adjust this value in production, or use tracesSampler for greater control
tracesSampleRate: 1.0,
integrations: [Sentry.localVariablesIntegration()],
});

Sentry.addEventProcessor(event => {
global.transactionIds = global.transactionIds || [];

if (event.type === 'transaction') {
const eventId = event.event_id;

if (eventId) {
global.transactionIds.push(eventId);
}
}

return event;
});
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as Sentry from '@sentry/nextjs';

export function register() {
if (process.env.NEXT_RUNTIME === 'nodejs' || process.env.NEXT_RUNTIME === 'edge') {
Sentry.init({
environment: 'qa', // dynamic sampling bias to keep transactions
dsn: process.env.NEXT_PUBLIC_E2E_TEST_DSN,
tunnel: `http://localhost:3031/`, // proxy server
tracesSampleRate: 1.0,
sendDefaultPii: true,
});
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as Sentry from '@sentry/nextjs';

export function register() {
if (process.env.NEXT_RUNTIME === 'nodejs' || process.env.NEXT_RUNTIME === 'edge') {
Sentry.init({
environment: 'qa', // dynamic sampling bias to keep transactions
dsn: process.env.NEXT_PUBLIC_E2E_TEST_DSN,
tunnel: `http://localhost:3031/`, // proxy server
tracesSampleRate: 1.0,
sendDefaultPii: true,
});
}
}

This file was deleted.

This file was deleted.

47 changes: 38 additions & 9 deletions packages/nextjs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,35 +17,64 @@

## Compatibility

Currently, the minimum Next.js supported version is `10.0.8`.
Currently, the minimum Next.js supported version is `11.2.0`.

## General

This package is a wrapper around `@sentry/node` for the server and `@sentry/react` for the client, with added
functionality related to Next.js.

To use this SDK, init it in the Sentry config files.
To use this SDK, initialize it in the Next.js configuration, in the `sentry.client.config.ts|js` file, and in the
[Next.js Instrumentation Hook](https://nextjs.org/docs/app/building-your-application/optimizing/instrumentation)
(`instrumentation.ts|js`).

```javascript
// sentry.client.config.js
// next.config.js

const { withSentryConfig } = require('@sentry/nextjs');

const nextConfig = {
experimental: {
// The instrumentation hook is required for Sentry to work on the serverside
instrumentationHook: true,
},
};

// Wrap the Next.js configuration with Sentry
module.exports = withSentryConfig(nextConfig);
```

```javascript
// sentry.client.config.js or .ts

import * as Sentry from '@sentry/nextjs';

Sentry.init({
dsn: '__DSN__',
// ...
// Your Sentry configuration for the Browser...
});
```

```javascript
// sentry.server.config.js
// instrumentation.ts

import * as Sentry from '@sentry/nextjs';

Sentry.init({
dsn: '__DSN__',
// ...
});
export function register() {
if (process.env.NEXT_RUNTIME === 'nodejs') {
Sentry.init({
dsn: '__DSN__',
// Your Node.js Sentry configuration...
});
}

if (process.env.NEXT_RUNTIME === 'edge') {
Sentry.init({
dsn: '__DSN__',
// Your Edge Runtime Sentry configuration...
});
}
}
```

To set context information or send manual events, use the exported functions of `@sentry/nextjs`.
Expand Down
2 changes: 2 additions & 0 deletions packages/nextjs/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ const config: PlaywrightTestConfig = {
cwd: path.join(__dirname, 'test', 'integration'),
command: 'yarn start',
port: 3000,
stdout: 'pipe',
stderr: 'pipe',
},
};

Expand Down
30 changes: 2 additions & 28 deletions packages/nextjs/src/config/loaders/wrappingLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ const middlewareWrapperTemplateCode = fs.readFileSync(middlewareWrapperTemplateP

let showedMissingAsyncStorageModuleWarning = false;

const sentryInitWrapperTemplatePath = path.resolve(__dirname, '..', 'templates', 'sentryInitWrapperTemplate.js');
const sentryInitWrapperTemplateCode = fs.readFileSync(sentryInitWrapperTemplatePath, { encoding: 'utf8' });

const serverComponentWrapperTemplatePath = path.resolve(
__dirname,
'..',
Expand All @@ -45,8 +42,7 @@ export type WrappingLoaderOptions = {
appDir: string | undefined;
pageExtensionRegex: string;
excludeServerRoutes: Array<RegExp | string>;
wrappingTargetKind: 'page' | 'api-route' | 'middleware' | 'server-component' | 'sentry-init' | 'route-handler';
sentryConfigFilePath?: string;
wrappingTargetKind: 'page' | 'api-route' | 'middleware' | 'server-component' | 'route-handler';
vercelCronsConfig?: VercelCronsConfig;
nextjsRequestAsyncStorageModulePath?: string;
};
Expand All @@ -70,7 +66,6 @@ export default function wrappingLoader(
pageExtensionRegex,
excludeServerRoutes = [],
wrappingTargetKind,
sentryConfigFilePath,
vercelCronsConfig,
nextjsRequestAsyncStorageModulePath,
} = 'getOptions' in this ? this.getOptions() : this.query;
Expand All @@ -79,28 +74,7 @@ export default function wrappingLoader(

let templateCode: string;

if (wrappingTargetKind === 'sentry-init') {
templateCode = sentryInitWrapperTemplateCode;

// Absolute paths to the sentry config do not work with Windows: https://github.com/getsentry/sentry-javascript/issues/8133
// Se we need check whether `this.resourcePath` is absolute because there is no contract by webpack that says it is absolute.
// Examples where `this.resourcePath` could possibly be non-absolute are virtual modules.
if (sentryConfigFilePath && path.isAbsolute(this.resourcePath)) {
const sentryConfigImportPath = path
.relative(path.dirname(this.resourcePath), sentryConfigFilePath)
.replace(/\\/g, '/');

// path.relative() may return something like `sentry.server.config.js` which is not allowed. Imports from the
// current directory need to start with './'.This is why we prepend the path with './', which should always again
// be a valid relative path.
// https://github.com/getsentry/sentry-javascript/issues/8798
templateCode = templateCode.replace(/__SENTRY_CONFIG_IMPORT_PATH__/g, `./${sentryConfigImportPath}`);
} else {
// Bail without doing any wrapping
this.callback(null, userCode, userModuleSourceMap);
return;
}
} else if (wrappingTargetKind === 'page' || wrappingTargetKind === 'api-route') {
if (wrappingTargetKind === 'page' || wrappingTargetKind === 'api-route') {
if (pagesDir === undefined) {
this.callback(null, userCode, userModuleSourceMap);
return;
Expand Down
4 changes: 4 additions & 0 deletions packages/nextjs/src/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ export type NextConfigObject = {
fallback?: NextRewrite[];
}
>;
// Next.js experimental options
experimental?: {
instrumentationHook?: boolean;
};
};

export type SentryBuildOptions = {
Expand Down

0 comments on commit 093531e

Please sign in to comment.