Skip to content

Commit ad05299

Browse files
committed
unify buildPluginOptions
1 parent c587947 commit ad05299

File tree

4 files changed

+133
-163
lines changed

4 files changed

+133
-163
lines changed

packages/nextjs/src/config/getBuildPluginOptions.ts

Lines changed: 108 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,103 @@
11
import type { Options as SentryBuildPluginOptions } from '@sentry/bundler-plugin-core';
22
import * as path from 'path';
3-
import type { SentryBuildOptions } from './types';
3+
import type { BuildContext, NextConfigObject, SentryBuildOptions } from './types';
44

55
/**
6-
* Get Sentry Build Plugin options for the runAfterProductionCompile hook.
6+
* Get Sentry Build Plugin options for both webpack and turbopack builds.
7+
* These options can be used in two ways:
8+
* 1. The build can be done in a single operation after the production build completes
9+
* 2. The build can be done in multiple operations, one for each webpack build
710
*/
811
export function getBuildPluginOptions({
912
sentryBuildOptions,
1013
releaseName,
1114
distDirAbsPath,
15+
buildTool,
16+
useRunAfterProductionCompileHook,
1217
}: {
1318
sentryBuildOptions: SentryBuildOptions;
1419
releaseName: string | undefined;
1520
distDirAbsPath: string;
21+
buildTool: 'webpack-client' | 'webpack-nodejs' | 'webpack-edge' | 'after-production-compile';
22+
useRunAfterProductionCompileHook?: boolean; // Whether the user has opted into using the experimental hook
1623
}): SentryBuildPluginOptions {
1724
const sourcemapUploadAssets: string[] = [];
1825
const sourcemapUploadIgnore: string[] = [];
19-
2026
const filesToDeleteAfterUpload: string[] = [];
2127

2228
// We need to convert paths to posix because Glob patterns use `\` to escape
2329
// glob characters. This clashes with Windows path separators.
2430
// See: https://www.npmjs.com/package/glob
2531
const normalizedDistDirAbsPath = distDirAbsPath.replace(/\\/g, '/');
2632

27-
sourcemapUploadAssets.push(
28-
path.posix.join(normalizedDistDirAbsPath, '**'), // Next.js build output
29-
);
30-
if (sentryBuildOptions.sourcemaps?.deleteSourcemapsAfterUpload) {
31-
filesToDeleteAfterUpload.push(
32-
path.posix.join(normalizedDistDirAbsPath, '**', '*.js.map'),
33-
path.posix.join(normalizedDistDirAbsPath, '**', '*.mjs.map'),
34-
path.posix.join(normalizedDistDirAbsPath, '**', '*.cjs.map'),
33+
const loggerPrefix = {
34+
'webpack-nodejs': '[@sentry/nextjs - Node.js]',
35+
'webpack-edge': '[@sentry/nextjs - Edge]',
36+
'webpack-client': '[@sentry/nextjs - Client]',
37+
'after-production-compile': '[@sentry/nextjs - After Production Compile]',
38+
}[buildTool];
39+
40+
if (buildTool === 'after-production-compile') {
41+
// Turbopack builds
42+
sourcemapUploadAssets.push(
43+
path.posix.join(normalizedDistDirAbsPath, '**'), // Next.js build output
3544
);
45+
46+
if (sentryBuildOptions.sourcemaps?.deleteSourcemapsAfterUpload) {
47+
filesToDeleteAfterUpload.push(
48+
path.posix.join(normalizedDistDirAbsPath, '**', '*.js.map'),
49+
path.posix.join(normalizedDistDirAbsPath, '**', '*.mjs.map'),
50+
path.posix.join(normalizedDistDirAbsPath, '**', '*.cjs.map'),
51+
);
52+
}
53+
} else {
54+
if (buildTool === 'webpack-nodejs' || buildTool === 'webpack-edge') {
55+
sourcemapUploadAssets.push(
56+
path.posix.join(distDirAbsPath, 'server', '**'), // Standard output location for server builds
57+
path.posix.join(distDirAbsPath, 'serverless', '**'), // Legacy output location for serverless Next.js
58+
);
59+
} else {
60+
// Client builds
61+
if (sentryBuildOptions.widenClientFileUpload) {
62+
sourcemapUploadAssets.push(path.posix.join(distDirAbsPath, 'static', 'chunks', '**'));
63+
} else {
64+
sourcemapUploadAssets.push(
65+
path.posix.join(distDirAbsPath, 'static', 'chunks', 'pages', '**'),
66+
path.posix.join(distDirAbsPath, 'static', 'chunks', 'app', '**'),
67+
);
68+
}
69+
70+
// We want to include main-* files if widenClientFileUpload is true as they have proven to be useful
71+
if (!sentryBuildOptions.widenClientFileUpload) {
72+
sourcemapUploadIgnore.push(path.posix.join(distDirAbsPath, 'static', 'chunks', 'main-*'));
73+
}
74+
75+
// Always ignore framework, polyfills, and webpack files
76+
sourcemapUploadIgnore.push(
77+
path.posix.join(distDirAbsPath, 'static', 'chunks', 'framework-*'),
78+
path.posix.join(distDirAbsPath, 'static', 'chunks', 'framework.*'),
79+
path.posix.join(distDirAbsPath, 'static', 'chunks', 'polyfills-*'),
80+
path.posix.join(distDirAbsPath, 'static', 'chunks', 'webpack-*'),
81+
);
82+
83+
// File deletion for webpack client builds
84+
if (sentryBuildOptions.sourcemaps?.deleteSourcemapsAfterUpload) {
85+
filesToDeleteAfterUpload.push(
86+
// We only care to delete client bundle source maps because they would be the ones being served.
87+
// Removing the server source maps crashes Vercel builds for (thus far) unknown reasons:
88+
// https://github.com/getsentry/sentry-javascript/issues/13099
89+
path.posix.join(distDirAbsPath, 'static', '**', '*.js.map'),
90+
path.posix.join(distDirAbsPath, 'static', '**', '*.mjs.map'),
91+
path.posix.join(distDirAbsPath, 'static', '**', '*.cjs.map'),
92+
);
93+
}
94+
}
3695
}
3796

97+
// If the user has opted into using the experimental hook, we skip sourcemaps and release management in the plugin
98+
// to avoid double sourcemap uploads.
99+
const shouldSkipSourcemapsUpload = useRunAfterProductionCompileHook && buildTool.startsWith('webpack');
100+
38101
return {
39102
authToken: sentryBuildOptions.authToken,
40103
headers: sentryBuildOptions.headers,
@@ -43,14 +106,17 @@ export function getBuildPluginOptions({
43106
telemetry: sentryBuildOptions.telemetry,
44107
debug: sentryBuildOptions.debug,
45108
errorHandler: sentryBuildOptions.errorHandler,
46-
reactComponentAnnotation: {
47-
...sentryBuildOptions.reactComponentAnnotation,
48-
...sentryBuildOptions.unstable_sentryWebpackPluginOptions?.reactComponentAnnotation,
49-
},
109+
reactComponentAnnotation:
110+
buildTool === 'after-production-compile'
111+
? undefined
112+
: {
113+
...sentryBuildOptions.reactComponentAnnotation,
114+
...sentryBuildOptions.unstable_sentryWebpackPluginOptions?.reactComponentAnnotation,
115+
},
50116
silent: sentryBuildOptions.silent,
51117
url: sentryBuildOptions.sentryUrl,
52118
sourcemaps: {
53-
disable: sentryBuildOptions.sourcemaps?.disable,
119+
disable: sentryBuildOptions.sourcemaps?.disable || shouldSkipSourcemapsUpload,
54120
rewriteSources(source) {
55121
if (source.startsWith('webpack://_N_E/')) {
56122
return source.replace('webpack://_N_E/', '');
@@ -62,7 +128,7 @@ export function getBuildPluginOptions({
62128
},
63129
assets: sentryBuildOptions.sourcemaps?.assets ?? sourcemapUploadAssets,
64130
ignore: sentryBuildOptions.sourcemaps?.ignore ?? sourcemapUploadIgnore,
65-
filesToDeleteAfterUpload,
131+
filesToDeleteAfterUpload: filesToDeleteAfterUpload.length > 0 ? filesToDeleteAfterUpload : undefined,
66132
...sentryBuildOptions.unstable_sentryWebpackPluginOptions?.sourcemaps,
67133
},
68134
release:
@@ -87,11 +153,35 @@ export function getBuildPluginOptions({
87153
...sentryBuildOptions.bundleSizeOptimizations,
88154
},
89155
_metaOptions: {
90-
loggerPrefixOverride: '[@sentry/nextjs]',
156+
loggerPrefixOverride: loggerPrefix,
91157
telemetry: {
92158
metaFramework: 'nextjs',
93159
},
94160
},
95161
...sentryBuildOptions.unstable_sentryWebpackPluginOptions,
96162
};
97163
}
164+
165+
/**
166+
* Legacy function for webpack builds. Now calls the unified getBuildPluginOptions function.
167+
* @deprecated Use getBuildPluginOptions instead
168+
*/
169+
export function getWebpackPluginOptions(
170+
buildContext: BuildContext,
171+
sentryBuildOptions: SentryBuildOptions,
172+
releaseName: string | undefined,
173+
): SentryBuildPluginOptions {
174+
const { isServer, config: userNextConfig, dir, nextRuntime } = buildContext;
175+
const buildTool = isServer ? (nextRuntime === 'edge' ? 'webpack-edge' : 'webpack-nodejs') : 'webpack-client';
176+
177+
const projectDir = dir.replace(/\\/g, '/');
178+
const distDir = (userNextConfig as NextConfigObject).distDir?.replace(/\\/g, '/') ?? '.next';
179+
const distDirAbsPath = path.posix.join(projectDir, distDir);
180+
181+
return getBuildPluginOptions({
182+
sentryBuildOptions,
183+
releaseName,
184+
distDirAbsPath,
185+
buildTool,
186+
});
187+
}

packages/nextjs/src/config/handleRunAfterProductionCompile.ts

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,6 @@ export async function handleRunAfterProductionCompile(
1111
{ releaseName, distDir, buildTool }: { releaseName?: string; distDir: string; buildTool: 'webpack' | 'turbopack' },
1212
sentryBuildOptions: SentryBuildOptions,
1313
): Promise<void> {
14-
// We don't want to do anything for webpack at this point because the plugin already handles this
15-
// TODO: Actually implement this for webpack as well
16-
if (buildTool === 'webpack') {
17-
return;
18-
}
19-
2014
if (sentryBuildOptions.debug) {
2115
// eslint-disable-next-line no-console
2216
console.debug('[@sentry/nextjs] Running runAfterProductionCompile logic.');
@@ -36,17 +30,17 @@ export async function handleRunAfterProductionCompile(
3630
return;
3731
}
3832

39-
const sentryBuildPluginManager = createSentryBuildPluginManager(
40-
getBuildPluginOptions({
41-
sentryBuildOptions,
42-
releaseName,
43-
distDirAbsPath: distDir,
44-
}),
45-
{
46-
buildTool,
47-
loggerPrefix: '[@sentry/nextjs]',
48-
},
49-
);
33+
const options = getBuildPluginOptions({
34+
sentryBuildOptions,
35+
releaseName,
36+
distDirAbsPath: distDir,
37+
buildTool: 'after-production-compile',
38+
});
39+
40+
const sentryBuildPluginManager = createSentryBuildPluginManager(options, {
41+
buildTool,
42+
loggerPrefix: '[@sentry/nextjs - After Production Compile]',
43+
});
5044

5145
await sentryBuildPluginManager.telemetry.emitBundlerPluginExecutionSignal();
5246
await sentryBuildPluginManager.createRelease();

packages/nextjs/src/config/webpack.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as fs from 'fs';
77
import * as path from 'path';
88
import { sync as resolveSync } from 'resolve';
99
import type { VercelCronsConfig } from '../common/types';
10+
import { getBuildPluginOptions } from './getBuildPluginOptions';
1011
import type { RouteManifest } from './manifest/types';
1112
// Note: If you need to import a type from Webpack, do it in `types.ts` and export it from there. Otherwise, our
1213
// circular dependency check thinks this file is importing from itself. See https://github.com/pahen/madge/issues/306.
@@ -22,7 +23,6 @@ import type {
2223
WebpackEntryProperty,
2324
} from './types';
2425
import { getNextjsVersion } from './util';
25-
import { getWebpackPluginOptions } from './webpackPluginOptions';
2626

2727
// Next.js runs webpack 3 times, once for the client, the server, and for edge. Because we don't want to print certain
2828
// warnings 3 times, we keep track of them here.
@@ -408,9 +408,21 @@ export function constructWebpackConfigFunction(
408408
}
409409

410410
newConfig.plugins = newConfig.plugins || [];
411+
const { config: userNextConfig, dir, nextRuntime } = buildContext;
412+
const buildTool = isServer ? (nextRuntime === 'edge' ? 'webpack-edge' : 'webpack-nodejs') : 'webpack-client';
413+
const projectDir = dir.replace(/\\/g, '/');
414+
const distDir = (userNextConfig as NextConfigObject).distDir?.replace(/\\/g, '/') ?? '.next';
415+
const distDirAbsPath = path.posix.join(projectDir, distDir);
416+
411417
const sentryWebpackPluginInstance = sentryWebpackPlugin(
412-
getWebpackPluginOptions(buildContext, userSentryOptions, releaseName),
418+
getBuildPluginOptions({
419+
sentryBuildOptions: userSentryOptions,
420+
releaseName,
421+
distDirAbsPath,
422+
buildTool,
423+
}),
413424
);
425+
414426
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
415427
sentryWebpackPluginInstance._name = 'sentry-webpack-plugin'; // For tests and debugging. Serves no other purpose.
416428
newConfig.plugins.push(sentryWebpackPluginInstance);

packages/nextjs/src/config/webpackPluginOptions.ts

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

0 commit comments

Comments
 (0)