Skip to content

Commit 093531e

Browse files
authored
feat(nextjs): Remove client.(server|client).config.ts functionality in favor of instrumentation.ts (#11059)
1 parent ffdc8aa commit 093531e

26 files changed

+287
-327
lines changed

MIGRATION.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,56 @@ setup for source maps in Sentry and will not require you to match stack frame pa
715715
To see the new options, check out the docs at https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/,
716716
or look at the TypeScript type definitions of `withSentryConfig`.
717717

718+
#### Updated the recommended way of calling `Sentry.init()`
719+
720+
With version 8 of the SDK we will no longer support the use of `sentry.server.config.ts` and `sentry.edge.config.ts`
721+
files. Instead, please initialize the Sentry Next.js SDK for the serverside in a
722+
[Next.js instrumentation hook](https://nextjs.org/docs/app/building-your-application/optimizing/instrumentation).
723+
**`sentry.client.config.ts|js` is still supported and encouraged for initializing the clientside SDK.**
724+
725+
The following is an example of how to initialize the serverside SDK in a Next.js instrumentation hook:
726+
727+
1. First, enable the Next.js instrumentation hook by setting the `experimental.instrumentationHook` to `true` in your
728+
`next.config.js`.
729+
2. Next, create a `instrumentation.ts|js` file in the root directory of your project (or in the `src` folder if you have
730+
have one).
731+
3. Now, export a `register` function from the `instrumentation.ts|js` file and call `Sentry.init()` inside of it:
732+
733+
```ts
734+
import * as Sentry from '@sentry/nextjs';
735+
736+
export function register() {
737+
if (process.env.NEXT_RUNTIME === 'nodejs') {
738+
Sentry.init({
739+
dsn: 'YOUR_DSN',
740+
// Your Node.js Sentry configuration...
741+
});
742+
}
743+
744+
if (process.env.NEXT_RUNTIME === 'edge') {
745+
Sentry.init({
746+
dsn: 'YOUR_DSN',
747+
// Your Edge Runtime Sentry configuration...
748+
});
749+
}
750+
}
751+
```
752+
753+
Note that you can initialize the SDK differently depending on which server runtime is being used.
754+
755+
If you are using a
756+
[Next.js custom server](https://nextjs.org/docs/pages/building-your-application/configuring/custom-server), the
757+
`instrumentation.ts` hook is not called by Next.js so you need to manually call it yourself from within your server
758+
code. It is recommended to do so as early as possible in your application lifecycle.
759+
760+
**Why are we making this change?** The very simple reason is that Next.js requires us to set up OpenTelemetry
761+
instrumentation inside the `register` function of the instrumentation hook. Looking a little bit further into the
762+
future, we also would like the Sentry SDK to be compatible with [Turbopack](https://turbo.build/pack), which is gonna be
763+
the bundler that Next.js will be using instead of Webpack. The SDK in its previous version depended heavily on Webpack
764+
in order to inject the `sentry.(server|edge).config.ts` files into the server-side code. Because this will not be
765+
possible in the future, we are doing ourselves a favor and doing things the way Next.js intends us to do them -
766+
hopefully reducing bugs and jank.
767+
718768
### Astro SDK
719769

720770
#### Removal of `trackHeaders` option for Astro middleware
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import * as Sentry from '@sentry/nextjs';
2+
3+
declare global {
4+
namespace globalThis {
5+
var transactionIds: string[];
6+
}
7+
}
8+
9+
export function register() {
10+
if (process.env.NEXT_RUNTIME === 'nodejs') {
11+
Sentry.init({
12+
environment: 'qa', // dynamic sampling bias to keep transactions
13+
dsn: process.env.NEXT_PUBLIC_E2E_TEST_DSN,
14+
// Adjust this value in production, or use tracesSampler for greater control
15+
tracesSampleRate: 1.0,
16+
integrations: [Sentry.localVariablesIntegration()],
17+
});
18+
19+
Sentry.addEventProcessor(event => {
20+
global.transactionIds = global.transactionIds || [];
21+
22+
if (event.type === 'transaction') {
23+
const eventId = event.event_id;
24+
25+
if (eventId) {
26+
global.transactionIds.push(eventId);
27+
}
28+
}
29+
30+
return event;
31+
});
32+
}
33+
}

dev-packages/e2e-tests/test-applications/create-next-app/sentry.server.config.ts

Lines changed: 0 additions & 33 deletions
This file was deleted.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import * as Sentry from '@sentry/nextjs';
2+
3+
export function register() {
4+
if (process.env.NEXT_RUNTIME === 'nodejs' || process.env.NEXT_RUNTIME === 'edge') {
5+
Sentry.init({
6+
environment: 'qa', // dynamic sampling bias to keep transactions
7+
dsn: process.env.NEXT_PUBLIC_E2E_TEST_DSN,
8+
tunnel: `http://localhost:3031/`, // proxy server
9+
tracesSampleRate: 1.0,
10+
sendDefaultPii: true,
11+
});
12+
}
13+
}

dev-packages/e2e-tests/test-applications/nextjs-14/sentry.edge.config.ts

Lines changed: 0 additions & 9 deletions
This file was deleted.

dev-packages/e2e-tests/test-applications/nextjs-14/sentry.server.config.ts

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import * as Sentry from '@sentry/nextjs';
2+
3+
export function register() {
4+
if (process.env.NEXT_RUNTIME === 'nodejs' || process.env.NEXT_RUNTIME === 'edge') {
5+
Sentry.init({
6+
environment: 'qa', // dynamic sampling bias to keep transactions
7+
dsn: process.env.NEXT_PUBLIC_E2E_TEST_DSN,
8+
tunnel: `http://localhost:3031/`, // proxy server
9+
tracesSampleRate: 1.0,
10+
sendDefaultPii: true,
11+
});
12+
}
13+
}

dev-packages/e2e-tests/test-applications/nextjs-app-dir/sentry.edge.config.ts

Lines changed: 0 additions & 9 deletions
This file was deleted.

dev-packages/e2e-tests/test-applications/nextjs-app-dir/sentry.server.config.ts

Lines changed: 0 additions & 9 deletions
This file was deleted.

packages/nextjs/README.md

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,35 +17,64 @@
1717

1818
## Compatibility
1919

20-
Currently, the minimum Next.js supported version is `10.0.8`.
20+
Currently, the minimum Next.js supported version is `11.2.0`.
2121

2222
## General
2323

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

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

2931
```javascript
30-
// sentry.client.config.js
32+
// next.config.js
33+
34+
const { withSentryConfig } = require('@sentry/nextjs');
35+
36+
const nextConfig = {
37+
experimental: {
38+
// The instrumentation hook is required for Sentry to work on the serverside
39+
instrumentationHook: true,
40+
},
41+
};
42+
43+
// Wrap the Next.js configuration with Sentry
44+
module.exports = withSentryConfig(nextConfig);
45+
```
46+
47+
```javascript
48+
// sentry.client.config.js or .ts
3149

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

3452
Sentry.init({
3553
dsn: '__DSN__',
36-
// ...
54+
// Your Sentry configuration for the Browser...
3755
});
3856
```
3957

4058
```javascript
41-
// sentry.server.config.js
59+
// instrumentation.ts
4260

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

45-
Sentry.init({
46-
dsn: '__DSN__',
47-
// ...
48-
});
63+
export function register() {
64+
if (process.env.NEXT_RUNTIME === 'nodejs') {
65+
Sentry.init({
66+
dsn: '__DSN__',
67+
// Your Node.js Sentry configuration...
68+
});
69+
}
70+
71+
if (process.env.NEXT_RUNTIME === 'edge') {
72+
Sentry.init({
73+
dsn: '__DSN__',
74+
// Your Edge Runtime Sentry configuration...
75+
});
76+
}
77+
}
4978
```
5079

5180
To set context information or send manual events, use the exported functions of `@sentry/nextjs`.

packages/nextjs/playwright.config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ const config: PlaywrightTestConfig = {
1515
cwd: path.join(__dirname, 'test', 'integration'),
1616
command: 'yarn start',
1717
port: 3000,
18+
stdout: 'pipe',
19+
stderr: 'pipe',
1820
},
1921
};
2022

packages/nextjs/src/config/loaders/wrappingLoader.ts

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@ const middlewareWrapperTemplateCode = fs.readFileSync(middlewareWrapperTemplateP
2626

2727
let showedMissingAsyncStorageModuleWarning = false;
2828

29-
const sentryInitWrapperTemplatePath = path.resolve(__dirname, '..', 'templates', 'sentryInitWrapperTemplate.js');
30-
const sentryInitWrapperTemplateCode = fs.readFileSync(sentryInitWrapperTemplatePath, { encoding: 'utf8' });
31-
3229
const serverComponentWrapperTemplatePath = path.resolve(
3330
__dirname,
3431
'..',
@@ -45,8 +42,7 @@ export type WrappingLoaderOptions = {
4542
appDir: string | undefined;
4643
pageExtensionRegex: string;
4744
excludeServerRoutes: Array<RegExp | string>;
48-
wrappingTargetKind: 'page' | 'api-route' | 'middleware' | 'server-component' | 'sentry-init' | 'route-handler';
49-
sentryConfigFilePath?: string;
45+
wrappingTargetKind: 'page' | 'api-route' | 'middleware' | 'server-component' | 'route-handler';
5046
vercelCronsConfig?: VercelCronsConfig;
5147
nextjsRequestAsyncStorageModulePath?: string;
5248
};
@@ -70,7 +66,6 @@ export default function wrappingLoader(
7066
pageExtensionRegex,
7167
excludeServerRoutes = [],
7268
wrappingTargetKind,
73-
sentryConfigFilePath,
7469
vercelCronsConfig,
7570
nextjsRequestAsyncStorageModulePath,
7671
} = 'getOptions' in this ? this.getOptions() : this.query;
@@ -79,28 +74,7 @@ export default function wrappingLoader(
7974

8075
let templateCode: string;
8176

82-
if (wrappingTargetKind === 'sentry-init') {
83-
templateCode = sentryInitWrapperTemplateCode;
84-
85-
// Absolute paths to the sentry config do not work with Windows: https://github.com/getsentry/sentry-javascript/issues/8133
86-
// Se we need check whether `this.resourcePath` is absolute because there is no contract by webpack that says it is absolute.
87-
// Examples where `this.resourcePath` could possibly be non-absolute are virtual modules.
88-
if (sentryConfigFilePath && path.isAbsolute(this.resourcePath)) {
89-
const sentryConfigImportPath = path
90-
.relative(path.dirname(this.resourcePath), sentryConfigFilePath)
91-
.replace(/\\/g, '/');
92-
93-
// path.relative() may return something like `sentry.server.config.js` which is not allowed. Imports from the
94-
// current directory need to start with './'.This is why we prepend the path with './', which should always again
95-
// be a valid relative path.
96-
// https://github.com/getsentry/sentry-javascript/issues/8798
97-
templateCode = templateCode.replace(/__SENTRY_CONFIG_IMPORT_PATH__/g, `./${sentryConfigImportPath}`);
98-
} else {
99-
// Bail without doing any wrapping
100-
this.callback(null, userCode, userModuleSourceMap);
101-
return;
102-
}
103-
} else if (wrappingTargetKind === 'page' || wrappingTargetKind === 'api-route') {
77+
if (wrappingTargetKind === 'page' || wrappingTargetKind === 'api-route') {
10478
if (pagesDir === undefined) {
10579
this.callback(null, userCode, userModuleSourceMap);
10680
return;

packages/nextjs/src/config/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ export type NextConfigObject = {
4343
fallback?: NextRewrite[];
4444
}
4545
>;
46+
// Next.js experimental options
47+
experimental?: {
48+
instrumentationHook?: boolean;
49+
};
4650
};
4751

4852
export type SentryBuildOptions = {

0 commit comments

Comments
 (0)