Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ const nextConfig: NextConfig = {};
export default withSentryConfig(nextConfig, {
silent: true,
applicationKey: 'nextjs-16-streaming-e2e',
reactComponentAnnotation: {
enabled: true,
},
_experimental: {
vercelCronsMonitoring: true,
turbopackReactComponentAnnotation: {
enabled: true,
},
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ const nextConfig: NextConfig = {
export default withSentryConfig(nextConfig, {
silent: true,
applicationKey: 'nextjs-16-e2e',
reactComponentAnnotation: {
enabled: true,
},
_experimental: {
vercelCronsMonitoring: true,
turbopackReactComponentAnnotation: {
enabled: true,
},
},
});
22 changes: 22 additions & 0 deletions docs/migration/v11-end-state.md
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,28 @@ The `console` option of `breadcrumbsIntegration` was removed. Use the `consoleIn

**Tracing removed from generated templates:** Tracing was removed from the generated Pages Router API handler, Edge API handler, and Middleware wrapper templates. Route handlers and middleware are still instrumented automatically, so no action is required for most users.

**Unified `reactComponentAnnotation` option:** React component annotation is now configured through a single top-level `reactComponentAnnotation` option that applies to both webpack and Turbopack builds:

```js
export default withSentryConfig(nextConfig, {
reactComponentAnnotation: {
enabled: true,
ignoredComponents: ['MyComponent'],
},
});
```

The two bundler-specific options it replaces are deprecated but still work, and will be removed in v12:

- `webpack.reactComponentAnnotation`
- `_experimental.turbopackReactComponentAnnotation`

If both a bundler-specific option and the top-level one are set, the bundler-specific one wins for that bundler.

Note that v10.30.0 deprecated a top-level `reactComponentAnnotation` in favour of `webpack.reactComponentAnnotation`, and v11 removed it. This reinstates the top-level option with broader meaning: it now drives Turbopack builds as well, which the old one never did. If you moved to `webpack.reactComponentAnnotation` for v10, moving back to the top level is the forward path.

On Turbopack, component annotation requires Next.js 16+. The SDK now warns at build time if annotation is enabled on an older Next.js version, where it previously did nothing silently.

### Cloudflare: `nodejs_compat` compatibility flag is now required

Affected SDKs: `@sentry/cloudflare`.
Expand Down
2 changes: 2 additions & 0 deletions packages/nextjs/src/config/getBuildPluginOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,8 @@ export function getBuildPluginOptions({
reactComponentAnnotation: buildTool.startsWith('after-production-compile')
? undefined
: {
...sentryBuildOptions.reactComponentAnnotation,
// eslint-disable-next-line typescript/no-deprecated
...sentryBuildOptions.webpack?.reactComponentAnnotation,
...sentryBuildOptions.webpack?.unstable_sentryWebpackPluginOptions?.reactComponentAnnotation,
},
Expand Down
49 changes: 32 additions & 17 deletions packages/nextjs/src/config/turbopack/constructTurbopackConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,24 +97,39 @@ export function constructTurbopackConfig({
}

// Add component annotation loader for react component name annotation in Turbopack builds.
// This is only added when turbopackReactComponentAnnotation.enabled is set AND the Next.js
// version supports the `condition` field in Turbopack rules (Next.js 16+).
const turbopackReactComponentAnnotation = userSentryOptions?._experimental?.turbopackReactComponentAnnotation;
if (turbopackReactComponentAnnotation?.enabled && nextJsVersion && supportsTurbopackRuleCondition(nextJsVersion)) {
newConfig.rules = safelyAddTurbopackRule(newConfig.rules, {
matcher: '*.{tsx,jsx}',
rule: {
condition: { not: 'foreign' },
loaders: [
{
loader: path.resolve(__dirname, '..', 'loaders', 'componentAnnotationLoader.js'),
options: {
ignoredComponents: turbopackReactComponentAnnotation.ignoredComponents ?? [],
// This is only added when annotation is enabled AND the Next.js version supports the
// `condition` field in Turbopack rules (Next.js 16+).
const reactComponentAnnotation = {
...userSentryOptions?.reactComponentAnnotation,
// eslint-disable-next-line typescript/no-deprecated
...userSentryOptions?._experimental?.turbopackReactComponentAnnotation,
};
if (reactComponentAnnotation.enabled) {
if (nextJsVersion && supportsTurbopackRuleCondition(nextJsVersion)) {
newConfig.rules = safelyAddTurbopackRule(newConfig.rules, {
matcher: '*.{tsx,jsx}',
rule: {
condition: { not: 'foreign' },
loaders: [
{
loader: path.resolve(__dirname, '..', 'loaders', 'componentAnnotationLoader.js'),
options: {
ignoredComponents: reactComponentAnnotation.ignoredComponents ?? [],
},
},
},
],
},
});
],
},
});
} else {
// Without this warning the option silently no-ops, which is indistinguishable from
// annotation being broken.
// eslint-disable-next-line no-console
console.warn(
`[@sentry/nextjs] \`reactComponentAnnotation\` is enabled but React component annotation requires Next.js 16+ on Turbopack builds${
nextJsVersion ? ` (detected ${nextJsVersion})` : ''
}. Your components will not be annotated.`,
);
}
}

newConfig.rules = maybeAddOrchestrionRule(newConfig.rules, userSentryOptions, nextJsVersion);
Expand Down
30 changes: 28 additions & 2 deletions packages/nextjs/src/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ export type SentryBuildWebpackOptions = {
* When enabled, your app's DOM will automatically be annotated during build-time with their respective component names.
* This will unlock the capability to search for Replays in Sentry by component name, as well as see component names in breadcrumbs and performance monitoring.
* Please note that this feature is not currently supported by the esbuild bundler plugins, and will only annotate React components
*
* @deprecated Use the top-level `reactComponentAnnotation` option instead, which works for both webpack and Turbopack builds.
*/
reactComponentAnnotation?: {
/**
Expand All @@ -171,7 +173,7 @@ export type SentryBuildWebpackOptions = {
* A list of strings representing the names of components to ignore. The plugin will not apply `data-sentry` annotations on the DOM element for these components.
*/
ignoredComponents?: string[];
};
}; // TODO(v12): remove this option
};

export type SentryBuildOptions = {
Expand Down Expand Up @@ -487,6 +489,28 @@ export type SentryBuildOptions = {
*/
applicationKey?: string;

/**
* Options related to react component name annotations.
* Disabled by default, unless a value is set for this option.
* When enabled, your app's DOM will automatically be annotated during build-time with their respective component names.
* This will unlock the capability to search for Replays in Sentry by component name, as well as see component names in
* breadcrumbs and performance monitoring.
*
* For webpack builds, this is forwarded to `@sentry/bundler-plugins/webpack`.
* For Turbopack builds, this applies the annotations via a custom loader and requires Next.js 16+.
*/
reactComponentAnnotation?: {
/**
* Whether the component name annotate plugin should be enabled or not.
*/
enabled?: boolean;

/**
* A list of strings representing the names of components to ignore. The plugin will not apply `data-sentry` annotations on the DOM element for these components.
*/
ignoredComponents?: string[];
};

/**
* Options to configure various bundle size optimizations related to the Sentry SDK.
*/
Expand Down Expand Up @@ -655,11 +679,13 @@ export type SentryBuildOptions = {
* When enabled, JSX elements are annotated with `data-sentry-component`,
* `data-sentry-element`, and `data-sentry-source-file` attributes.
* Requires Next.js 16+.
*
* @deprecated Use the top-level `reactComponentAnnotation` option instead, which works for both webpack and Turbopack builds.
*/
turbopackReactComponentAnnotation?: {
enabled?: boolean;
ignoredComponents?: string[];
};
}; // TODO(v12): remove this option
}>;

/**
Expand Down
52 changes: 52 additions & 0 deletions packages/nextjs/test/config/getBuildPluginOptions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,58 @@ describe('getBuildPluginOptions', () => {
});

describe('react component annotation', () => {
it('forwards the top-level option to the webpack plugin', () => {
const sentryBuildOptions: SentryBuildOptions = {
org: 'test-org',
project: 'test-project',
reactComponentAnnotation: {
enabled: true,
ignoredComponents: ['Header'],
},
};

const result = getBuildPluginOptions({
sentryBuildOptions,
releaseName: mockReleaseName,
distDirAbsPath: mockDistDirAbsPath,
buildTool: 'webpack-client',
});

expect(result.reactComponentAnnotation).toEqual({
enabled: true,
ignoredComponents: ['Header'],
});
});

it('lets the deprecated webpack-scoped option override the top-level one', () => {
const sentryBuildOptions: SentryBuildOptions = {
org: 'test-org',
project: 'test-project',
reactComponentAnnotation: {
enabled: true,
ignoredComponents: ['TopLevel'],
},
webpack: {
reactComponentAnnotation: {
ignoredComponents: ['Scoped'],
},
},
};

const result = getBuildPluginOptions({
sentryBuildOptions,
releaseName: mockReleaseName,
distDirAbsPath: mockDistDirAbsPath,
buildTool: 'webpack-client',
});

// Merged field-wise: `enabled` comes from the top level, `ignoredComponents` from the scoped option
expect(result.reactComponentAnnotation).toEqual({
enabled: true,
ignoredComponents: ['Scoped'],
});
});

it('merges react component annotation options correctly for webpack builds', () => {
const sentryBuildOptions: SentryBuildOptions = {
org: 'test-org',
Expand Down
Loading
Loading