Skip to content

Commit fae0682

Browse files
authored
fix(nextjs): Use absolute path for distDir in webpack plugin options (#6214)
In nextjs, the output directory (`distDir`) is specified by the user and stored in memory as a relative path. It's then used in two places: - At build time, it's resolved against the project directory, in order to know where to output built files. - At runtime, it's resolved against the working directory, in order to know where to find those built files. In the nextjs SDK, we also use the value in two places: - At build time, we pass it to `@sentry/cli` via Sentry webpack plugin options. `sentry/cli` then resolves it against its working directory, so that it knows where to find built files to upload. - At runtime, we grab it from `global.__rewriteFramesDistDir__` (where we've stashed it at build time via our prefix loader), and then resolve it against the working directory, so the `RewriteFrames` integration knows what value to strip from stackframe paths. At runtime, this resolution always works, because it matches what nextjs itself does. At build time, it also works... most of the time. But in the case where the project directory and `@sentry/cli`'s working directory don't match, it leads to `@sentry/cli` not being able to find the files it needs to upload. (This can happen if, for example, the app is a package in a monorepo - located at `packages/nextjsApp`, say - and `@sentry/cli` is running from the monorepo's root level `node_modules`.) This fixes that by resolving the `distDir` value against the project directory (thereby turning it into an absolute path) before passing it to `@sentry/cli`. That way, no resolution on `@sentry/cli`'s part is necessary, preventing the mismatch. Fixes the problem outlined in #6194.
1 parent a051985 commit fae0682

File tree

2 files changed

+36
-24
lines changed

2 files changed

+36
-24
lines changed

packages/nextjs/src/config/webpack.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -452,22 +452,22 @@ export function getWebpackPluginOptions(
452452
const { buildId, isServer, webpack, config, dev: isDev, dir: projectDir } = buildContext;
453453
const userNextConfig = config as NextConfigObject;
454454

455-
const distDir = userNextConfig.distDir ?? '.next'; // `.next` is the default directory
455+
const distDirAbsPath = path.resolve(projectDir, userNextConfig.distDir || '.next'); // `.next` is the default directory
456456

457457
const isWebpack5 = webpack.version.startsWith('5');
458458
const isServerless = userNextConfig.target === 'experimental-serverless-trace';
459459
const hasSentryProperties = fs.existsSync(path.resolve(projectDir, 'sentry.properties'));
460460
const urlPrefix = userNextConfig.basePath ? `~${userNextConfig.basePath}/_next` : '~/_next';
461461

462462
const serverInclude = isServerless
463-
? [{ paths: [`${distDir}/serverless/`], urlPrefix: `${urlPrefix}/serverless` }]
464-
: [{ paths: [`${distDir}/server/pages/`], urlPrefix: `${urlPrefix}/server/pages` }].concat(
465-
isWebpack5 ? [{ paths: [`${distDir}/server/chunks/`], urlPrefix: `${urlPrefix}/server/chunks` }] : [],
463+
? [{ paths: [`${distDirAbsPath}/serverless/`], urlPrefix: `${urlPrefix}/serverless` }]
464+
: [{ paths: [`${distDirAbsPath}/server/pages/`], urlPrefix: `${urlPrefix}/server/pages` }].concat(
465+
isWebpack5 ? [{ paths: [`${distDirAbsPath}/server/chunks/`], urlPrefix: `${urlPrefix}/server/chunks` }] : [],
466466
);
467467

468468
const clientInclude = userSentryOptions.widenClientFileUpload
469-
? [{ paths: [`${distDir}/static/chunks`], urlPrefix: `${urlPrefix}/static/chunks` }]
470-
: [{ paths: [`${distDir}/static/chunks/pages`], urlPrefix: `${urlPrefix}/static/chunks/pages` }];
469+
? [{ paths: [`${distDirAbsPath}/static/chunks`], urlPrefix: `${urlPrefix}/static/chunks` }]
470+
: [{ paths: [`${distDirAbsPath}/static/chunks/pages`], urlPrefix: `${urlPrefix}/static/chunks/pages` }];
471471

472472
const defaultPluginOptions = dropUndefinedKeys({
473473
include: isServer ? serverInclude : clientInclude,

packages/nextjs/test/config/webpack/sentryWebpackPlugin.test.ts

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,18 @@ describe('Sentry webpack plugin config', () => {
7777
) as SentryWebpackPlugin;
7878

7979
expect(sentryWebpackPluginInstance.options.include).toEqual([
80-
{ paths: ['.next/static/chunks/pages'], urlPrefix: '~/_next/static/chunks/pages' },
80+
{ paths: [`${clientBuildContext.dir}/.next/static/chunks/pages`], urlPrefix: '~/_next/static/chunks/pages' },
8181
]);
8282
});
8383

8484
it('has the correct value when building client bundles using `widenClientFileUpload` option', async () => {
8585
const exportedNextConfigWithWidening = { ...exportedNextConfig, sentry: { widenClientFileUpload: true } };
86+
const buildContext = getBuildContext('client', exportedNextConfigWithWidening);
87+
8688
const finalWebpackConfig = await materializeFinalWebpackConfig({
8789
exportedNextConfig: exportedNextConfigWithWidening,
8890
incomingWebpackConfig: clientWebpackConfig,
89-
incomingWebpackBuildContext: getBuildContext('client', exportedNextConfigWithWidening),
91+
incomingWebpackBuildContext: buildContext,
9092
});
9193

9294
const sentryWebpackPluginInstance = findWebpackPlugin(
@@ -95,7 +97,7 @@ describe('Sentry webpack plugin config', () => {
9597
) as SentryWebpackPlugin;
9698

9799
expect(sentryWebpackPluginInstance.options.include).toEqual([
98-
{ paths: ['.next/static/chunks'], urlPrefix: '~/_next/static/chunks' },
100+
{ paths: [`${buildContext.dir}/.next/static/chunks`], urlPrefix: '~/_next/static/chunks' },
99101
]);
100102
});
101103

@@ -104,11 +106,12 @@ describe('Sentry webpack plugin config', () => {
104106
...exportedNextConfig,
105107
target: 'experimental-serverless-trace' as const,
106108
};
109+
const buildContext = getBuildContext('server', exportedNextConfigServerless);
107110

108111
const finalWebpackConfig = await materializeFinalWebpackConfig({
109112
exportedNextConfig: exportedNextConfigServerless,
110113
incomingWebpackConfig: serverWebpackConfig,
111-
incomingWebpackBuildContext: getBuildContext('server', exportedNextConfigServerless),
114+
incomingWebpackBuildContext: buildContext,
112115
});
113116

114117
const sentryWebpackPluginInstance = findWebpackPlugin(
@@ -117,7 +120,7 @@ describe('Sentry webpack plugin config', () => {
117120
) as SentryWebpackPlugin;
118121

119122
expect(sentryWebpackPluginInstance.options.include).toEqual([
120-
{ paths: ['.next/serverless/'], urlPrefix: '~/_next/serverless' },
123+
{ paths: [`${buildContext.dir}/.next/serverless/`], urlPrefix: '~/_next/serverless' },
121124
]);
122125
});
123126

@@ -137,7 +140,7 @@ describe('Sentry webpack plugin config', () => {
137140
) as SentryWebpackPlugin;
138141

139142
expect(sentryWebpackPluginInstance.options.include).toEqual([
140-
{ paths: ['.next/server/pages/'], urlPrefix: '~/_next/server/pages' },
143+
{ paths: [`${serverBuildContextWebpack4.dir}/.next/server/pages/`], urlPrefix: '~/_next/server/pages' },
141144
]);
142145
});
143146

@@ -154,8 +157,8 @@ describe('Sentry webpack plugin config', () => {
154157
) as SentryWebpackPlugin;
155158

156159
expect(sentryWebpackPluginInstance.options.include).toEqual([
157-
{ paths: ['.next/server/pages/'], urlPrefix: '~/_next/server/pages' },
158-
{ paths: ['.next/server/chunks/'], urlPrefix: '~/_next/server/chunks' },
160+
{ paths: [`${serverBuildContext.dir}/.next/server/pages/`], urlPrefix: '~/_next/server/pages' },
161+
{ paths: [`${serverBuildContext.dir}/.next/server/chunks/`], urlPrefix: '~/_next/server/chunks' },
159162
]);
160163
});
161164
});
@@ -206,10 +209,11 @@ describe('Sentry webpack plugin config', () => {
206209
};
207210

208211
it('has the correct value when building client bundles', async () => {
212+
const buildContext = getBuildContext('client', exportedNextConfigWithBasePath);
209213
const finalWebpackConfig = await materializeFinalWebpackConfig({
210214
exportedNextConfig: exportedNextConfigWithBasePath,
211215
incomingWebpackConfig: clientWebpackConfig,
212-
incomingWebpackBuildContext: getBuildContext('client', exportedNextConfigWithBasePath),
216+
incomingWebpackBuildContext: buildContext,
213217
});
214218

215219
const sentryWebpackPluginInstance = findWebpackPlugin(
@@ -218,7 +222,10 @@ describe('Sentry webpack plugin config', () => {
218222
) as SentryWebpackPlugin;
219223

220224
expect(sentryWebpackPluginInstance.options.include).toEqual([
221-
{ paths: ['.next/static/chunks/pages'], urlPrefix: '~/city-park/_next/static/chunks/pages' },
225+
{
226+
paths: [`${buildContext.dir}/.next/static/chunks/pages`],
227+
urlPrefix: '~/city-park/_next/static/chunks/pages',
228+
},
222229
]);
223230
});
224231

@@ -227,11 +234,12 @@ describe('Sentry webpack plugin config', () => {
227234
...exportedNextConfigWithBasePath,
228235
target: 'experimental-serverless-trace' as const,
229236
};
237+
const buildContext = getBuildContext('server', exportedNextConfigServerless);
230238

231239
const finalWebpackConfig = await materializeFinalWebpackConfig({
232240
exportedNextConfig: exportedNextConfigServerless,
233241
incomingWebpackConfig: serverWebpackConfig,
234-
incomingWebpackBuildContext: getBuildContext('server', exportedNextConfigServerless),
242+
incomingWebpackBuildContext: buildContext,
235243
});
236244

237245
const sentryWebpackPluginInstance = findWebpackPlugin(
@@ -240,7 +248,7 @@ describe('Sentry webpack plugin config', () => {
240248
) as SentryWebpackPlugin;
241249

242250
expect(sentryWebpackPluginInstance.options.include).toEqual([
243-
{ paths: ['.next/serverless/'], urlPrefix: '~/city-park/_next/serverless' },
251+
{ paths: [`${buildContext.dir}/.next/serverless/`], urlPrefix: '~/city-park/_next/serverless' },
244252
]);
245253
});
246254

@@ -260,15 +268,19 @@ describe('Sentry webpack plugin config', () => {
260268
) as SentryWebpackPlugin;
261269

262270
expect(sentryWebpackPluginInstance.options.include).toEqual([
263-
{ paths: ['.next/server/pages/'], urlPrefix: '~/city-park/_next/server/pages' },
271+
{
272+
paths: [`${serverBuildContextWebpack4.dir}/.next/server/pages/`],
273+
urlPrefix: '~/city-park/_next/server/pages',
274+
},
264275
]);
265276
});
266277

267278
it('has the correct value when building serverful server bundles using webpack 5', async () => {
279+
const buildContext = getBuildContext('server', exportedNextConfigWithBasePath);
268280
const finalWebpackConfig = await materializeFinalWebpackConfig({
269281
exportedNextConfig: exportedNextConfigWithBasePath,
270282
incomingWebpackConfig: serverWebpackConfig,
271-
incomingWebpackBuildContext: getBuildContext('server', exportedNextConfigWithBasePath),
283+
incomingWebpackBuildContext: buildContext,
272284
});
273285

274286
const sentryWebpackPluginInstance = findWebpackPlugin(
@@ -277,8 +289,8 @@ describe('Sentry webpack plugin config', () => {
277289
) as SentryWebpackPlugin;
278290

279291
expect(sentryWebpackPluginInstance.options.include).toEqual([
280-
{ paths: ['.next/server/pages/'], urlPrefix: '~/city-park/_next/server/pages' },
281-
{ paths: ['.next/server/chunks/'], urlPrefix: '~/city-park/_next/server/chunks' },
292+
{ paths: [`${buildContext.dir}/.next/server/pages/`], urlPrefix: '~/city-park/_next/server/pages' },
293+
{ paths: [`${buildContext.dir}/.next/server/chunks/`], urlPrefix: '~/city-park/_next/server/chunks' },
282294
]);
283295
});
284296
});
@@ -450,7 +462,7 @@ describe('Sentry webpack plugin config', () => {
450462

451463
for (const pathDescriptor of includePaths) {
452464
for (const path of pathDescriptor.paths) {
453-
expect(path).toMatch(new RegExp(`^${expectedDistDir}.*`));
465+
expect(path).toMatch(new RegExp(`${buildContext.dir}/${expectedDistDir}.*`));
454466
}
455467
}
456468
});
@@ -469,7 +481,7 @@ describe('Sentry webpack plugin config', () => {
469481

470482
for (const pathDescriptor of includePaths) {
471483
for (const path of pathDescriptor.paths) {
472-
expect(path).toMatch(new RegExp(`^${expectedDistDir}.*`));
484+
expect(path).toMatch(new RegExp(`${buildContext.dir}/${expectedDistDir}.*`));
473485
}
474486
}
475487
});

0 commit comments

Comments
 (0)