Skip to content

Commit

Permalink
fix(nextjs): Use absolute path for distDir in webpack plugin options (
Browse files Browse the repository at this point in the history
#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.
  • Loading branch information
lobsterkatie committed Nov 16, 2022
1 parent a051985 commit fae0682
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 24 deletions.
12 changes: 6 additions & 6 deletions packages/nextjs/src/config/webpack.ts
Expand Up @@ -452,22 +452,22 @@ export function getWebpackPluginOptions(
const { buildId, isServer, webpack, config, dev: isDev, dir: projectDir } = buildContext;
const userNextConfig = config as NextConfigObject;

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

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

const serverInclude = isServerless
? [{ paths: [`${distDir}/serverless/`], urlPrefix: `${urlPrefix}/serverless` }]
: [{ paths: [`${distDir}/server/pages/`], urlPrefix: `${urlPrefix}/server/pages` }].concat(
isWebpack5 ? [{ paths: [`${distDir}/server/chunks/`], urlPrefix: `${urlPrefix}/server/chunks` }] : [],
? [{ paths: [`${distDirAbsPath}/serverless/`], urlPrefix: `${urlPrefix}/serverless` }]
: [{ paths: [`${distDirAbsPath}/server/pages/`], urlPrefix: `${urlPrefix}/server/pages` }].concat(
isWebpack5 ? [{ paths: [`${distDirAbsPath}/server/chunks/`], urlPrefix: `${urlPrefix}/server/chunks` }] : [],
);

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

const defaultPluginOptions = dropUndefinedKeys({
include: isServer ? serverInclude : clientInclude,
Expand Down
48 changes: 30 additions & 18 deletions packages/nextjs/test/config/webpack/sentryWebpackPlugin.test.ts
Expand Up @@ -77,16 +77,18 @@ describe('Sentry webpack plugin config', () => {
) as SentryWebpackPlugin;

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

it('has the correct value when building client bundles using `widenClientFileUpload` option', async () => {
const exportedNextConfigWithWidening = { ...exportedNextConfig, sentry: { widenClientFileUpload: true } };
const buildContext = getBuildContext('client', exportedNextConfigWithWidening);

const finalWebpackConfig = await materializeFinalWebpackConfig({
exportedNextConfig: exportedNextConfigWithWidening,
incomingWebpackConfig: clientWebpackConfig,
incomingWebpackBuildContext: getBuildContext('client', exportedNextConfigWithWidening),
incomingWebpackBuildContext: buildContext,
});

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

expect(sentryWebpackPluginInstance.options.include).toEqual([
{ paths: ['.next/static/chunks'], urlPrefix: '~/_next/static/chunks' },
{ paths: [`${buildContext.dir}/.next/static/chunks`], urlPrefix: '~/_next/static/chunks' },
]);
});

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

const finalWebpackConfig = await materializeFinalWebpackConfig({
exportedNextConfig: exportedNextConfigServerless,
incomingWebpackConfig: serverWebpackConfig,
incomingWebpackBuildContext: getBuildContext('server', exportedNextConfigServerless),
incomingWebpackBuildContext: buildContext,
});

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

expect(sentryWebpackPluginInstance.options.include).toEqual([
{ paths: ['.next/serverless/'], urlPrefix: '~/_next/serverless' },
{ paths: [`${buildContext.dir}/.next/serverless/`], urlPrefix: '~/_next/serverless' },
]);
});

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

expect(sentryWebpackPluginInstance.options.include).toEqual([
{ paths: ['.next/server/pages/'], urlPrefix: '~/_next/server/pages' },
{ paths: [`${serverBuildContextWebpack4.dir}/.next/server/pages/`], urlPrefix: '~/_next/server/pages' },
]);
});

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

expect(sentryWebpackPluginInstance.options.include).toEqual([
{ paths: ['.next/server/pages/'], urlPrefix: '~/_next/server/pages' },
{ paths: ['.next/server/chunks/'], urlPrefix: '~/_next/server/chunks' },
{ paths: [`${serverBuildContext.dir}/.next/server/pages/`], urlPrefix: '~/_next/server/pages' },
{ paths: [`${serverBuildContext.dir}/.next/server/chunks/`], urlPrefix: '~/_next/server/chunks' },
]);
});
});
Expand Down Expand Up @@ -206,10 +209,11 @@ describe('Sentry webpack plugin config', () => {
};

it('has the correct value when building client bundles', async () => {
const buildContext = getBuildContext('client', exportedNextConfigWithBasePath);
const finalWebpackConfig = await materializeFinalWebpackConfig({
exportedNextConfig: exportedNextConfigWithBasePath,
incomingWebpackConfig: clientWebpackConfig,
incomingWebpackBuildContext: getBuildContext('client', exportedNextConfigWithBasePath),
incomingWebpackBuildContext: buildContext,
});

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

expect(sentryWebpackPluginInstance.options.include).toEqual([
{ paths: ['.next/static/chunks/pages'], urlPrefix: '~/city-park/_next/static/chunks/pages' },
{
paths: [`${buildContext.dir}/.next/static/chunks/pages`],
urlPrefix: '~/city-park/_next/static/chunks/pages',
},
]);
});

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

const finalWebpackConfig = await materializeFinalWebpackConfig({
exportedNextConfig: exportedNextConfigServerless,
incomingWebpackConfig: serverWebpackConfig,
incomingWebpackBuildContext: getBuildContext('server', exportedNextConfigServerless),
incomingWebpackBuildContext: buildContext,
});

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

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

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

expect(sentryWebpackPluginInstance.options.include).toEqual([
{ paths: ['.next/server/pages/'], urlPrefix: '~/city-park/_next/server/pages' },
{
paths: [`${serverBuildContextWebpack4.dir}/.next/server/pages/`],
urlPrefix: '~/city-park/_next/server/pages',
},
]);
});

it('has the correct value when building serverful server bundles using webpack 5', async () => {
const buildContext = getBuildContext('server', exportedNextConfigWithBasePath);
const finalWebpackConfig = await materializeFinalWebpackConfig({
exportedNextConfig: exportedNextConfigWithBasePath,
incomingWebpackConfig: serverWebpackConfig,
incomingWebpackBuildContext: getBuildContext('server', exportedNextConfigWithBasePath),
incomingWebpackBuildContext: buildContext,
});

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

expect(sentryWebpackPluginInstance.options.include).toEqual([
{ paths: ['.next/server/pages/'], urlPrefix: '~/city-park/_next/server/pages' },
{ paths: ['.next/server/chunks/'], urlPrefix: '~/city-park/_next/server/chunks' },
{ paths: [`${buildContext.dir}/.next/server/pages/`], urlPrefix: '~/city-park/_next/server/pages' },
{ paths: [`${buildContext.dir}/.next/server/chunks/`], urlPrefix: '~/city-park/_next/server/chunks' },
]);
});
});
Expand Down Expand Up @@ -450,7 +462,7 @@ describe('Sentry webpack plugin config', () => {

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

for (const pathDescriptor of includePaths) {
for (const path of pathDescriptor.paths) {
expect(path).toMatch(new RegExp(`^${expectedDistDir}.*`));
expect(path).toMatch(new RegExp(`${buildContext.dir}/${expectedDistDir}.*`));
}
}
});
Expand Down

0 comments on commit fae0682

Please sign in to comment.