Skip to content
Draft
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
@@ -0,0 +1,3 @@
body {
font-family: sans-serif;
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import './globals.css';
import Link from 'next/link';
import { SpanContextProvider } from '../components/span-context';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as fs from 'fs';
import * as path from 'path';
import * as assert from 'assert/strict';
import { findSourceMapFiles } from '@sentry-internal/test-utils';
import { findSourceMapFiles, findSourceMappingUrlComments } from '@sentry-internal/test-utils';

const nextPackageJson = require('next/package.json');
const nextjsVersion = nextPackageJson.version;
Expand Down Expand Up @@ -47,4 +47,12 @@ const getLatestNextVersion = async () => {
[],
'Client bundle .map files found even though `sourcemaps.deleteSourcemapsAfterUpload` option is set!',
);
assert.deepEqual(
findSourceMappingUrlComments({
outputDir: path.join('.next', 'static'),
extensions: ['.js', '.mjs', '.cjs', '.css'],
}),
[],
'Client bundles reference source maps even though `sourcemaps.deleteSourcemapsAfterUpload` option is set!',
);
})();
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as fs from 'fs';
import * as path from 'path';
import * as assert from 'assert/strict';
import { findSourceMapFiles } from '@sentry-internal/test-utils';
import { findSourceMapFiles, findSourceMappingUrlComments } from '@sentry-internal/test-utils';

const nextPackageJson = require('next/package.json');
const nextjsVersion = nextPackageJson.version;
Expand Down Expand Up @@ -39,4 +39,12 @@ const getLatestNextVersion = async () => {
[],
'Client bundle .map files found even though `sourcemaps.deleteSourcemapsAfterUpload` option is set!',
);
assert.deepEqual(
findSourceMappingUrlComments({
outputDir: path.join('.next', 'static'),
extensions: ['.js', '.mjs', '.cjs', '.css'],
}),
[],
'Client bundles reference source maps even though `sourcemaps.deleteSourcemapsAfterUpload` option is set!',
);
})();
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.page {
font-family: sans-serif;
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import Link from 'next/link';
import { ClientErrorDebugTools } from '../components/client-error-debug-tools';
import styles from '../components/page.module.css';

export default function Page() {
return (
<div>
<div className={styles.page}>
<h2>Page (/)</h2>
<ClientErrorDebugTools />
<Link href="/user/5" id="navigation">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body {
font-family: sans-serif;
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import './globals.css';
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ if (process.env.E2E_DELETE_SOURCEMAPS) {
const staticDir = '.next/static';
assert.deepEqual(findSourceMapFiles({ outputDir: staticDir }), [], `Expected no source maps in ${staticDir}`);
assert.deepEqual(
findSourceMappingUrlComments({ outputDir: staticDir }),
findSourceMappingUrlComments({ outputDir: staticDir, extensions: ['.js', '.mjs', '.cjs', '.css'] }),
[],
`Expected no sourceMappingURL comments in ${staticDir}`,
);
Expand Down
57 changes: 37 additions & 20 deletions packages/nextjs/src/config/getBuildPluginOptions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Options as SentryBuildPluginOptions } from '@sentry/bundler-plugins/core';
import type { InternalOptions as SentryBuildPluginOptions } from '@sentry/bundler-plugins/core';
import * as fs from 'fs';
import * as path from 'path';
import { getBuildLogger } from './buildLogger';
Expand Down Expand Up @@ -179,30 +179,39 @@ function createSourcemapUploadIgnorePattern(
}

/**
* Creates file patterns for deletion after source map upload
* Creates file patterns for deletion after the source map upload that runs after the production compile.
* The webpack plugin removes the maps of webpack builds itself (see `deleteSourcemapsAfterUpload`).
*/
function createFilesToDeleteAfterUploadPattern(
normalizedDistPath: string,
buildTool: BuildTool,
deleteSourcemapsAfterUpload: boolean,
useRunAfterProductionCompileHook: boolean = false,
): string[] | undefined {
if (!deleteSourcemapsAfterUpload) {
if (!deleteSourcemapsAfterUpload || !buildTool.startsWith('after-production-compile')) {
return undefined;
}

return SOURCEMAP_EXTENSIONS.map(ext => path.posix.join(normalizedDistPath, 'static', '**', ext));
}

/**
* Whether the webpack plugin removes the source maps of this compiler from the build output.
*/
function shouldWebpackPluginDeleteSourcemaps(
buildTool: BuildTool,
deleteSourcemapsAfterUpload: boolean,
userFilesToDeleteAfterUpload: string | string[] | undefined,
useRunAfterProductionCompileHook: boolean = false,
): boolean {
// We don't want to delete source maps for server builds as this led to errors on Vercel in the past
// See: https://github.com/getsentry/sentry-javascript/issues/13099
if (buildTool === 'webpack-nodejs' || buildTool === 'webpack-edge') {
return undefined;
}

// Skip deletion for webpack client builds when using the experimental hook
if (buildTool === 'webpack-client' && useRunAfterProductionCompileHook) {
return undefined;
}

return SOURCEMAP_EXTENSIONS.map(ext => path.posix.join(normalizedDistPath, 'static', '**', ext));
// With the hook, the upload runs after the compile and must still find the maps.
return (
buildTool === 'webpack-client' &&
!useRunAfterProductionCompileHook &&
userFilesToDeleteAfterUpload === undefined &&
deleteSourcemapsAfterUpload
);
}

/**
Expand Down Expand Up @@ -313,15 +322,19 @@ export function getBuildPluginOptions({
? Array.isArray(userFilesToDeleteAfterUpload)
? userFilesToDeleteAfterUpload
: [userFilesToDeleteAfterUpload]
: createFilesToDeleteAfterUploadPattern(
normalizedDistDirAbsPath,
buildTool,
deleteSourcemapsAfterUpload,
useRunAfterProductionCompileHook,
);
: createFilesToDeleteAfterUploadPattern(normalizedDistDirAbsPath, buildTool, deleteSourcemapsAfterUpload);

const skipSourcemapsUpload = shouldSkipSourcemapUpload(buildTool, useRunAfterProductionCompileHook);

const webpackPluginDeletesSourcemaps = buildTool.startsWith('webpack')
? shouldWebpackPluginDeleteSourcemaps(
buildTool,
deleteSourcemapsAfterUpload,
userFilesToDeleteAfterUpload,
useRunAfterProductionCompileHook,
)
: undefined;

return {
// Only the browser reads these tags (`thirdPartyErrorFilterIntegration`), so server bundles skip the per-module cost.
applicationKey:
Expand All @@ -348,6 +361,10 @@ export function getBuildPluginOptions({
assets: sentryBuildOptions.sourcemaps?.assets ?? sourcemapUploadAssets,
ignore: finalIgnorePatterns,
filesToDeleteAfterUpload,
deleteSourcemapsAfterUpload: webpackPluginDeletesSourcemaps,
// Every client map goes, also those the user turned on with `productionBrowserSourceMaps` or
// `devtool`, and those of chunks the upload leaves out.
sdkEnabledSourceMaps: webpackPluginDeletesSourcemaps,
resolveSourceMap: sentryBuildOptions.sourcemaps?.resolveSourceMap,
},
release: createReleaseConfig(releaseName, sentryBuildOptions),
Expand Down
13 changes: 6 additions & 7 deletions packages/nextjs/src/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -462,16 +462,15 @@ type SentryBuildSourceMapsOptions = Omit<
filesToDeleteAfterUpload?: string | string[];

/**
* Toggle whether generated source maps within your Next.js build folder should be automatically deleted after being
* uploaded to Sentry.
* Toggle whether the client source maps within your Next.js build folder should be automatically deleted after
* being uploaded to Sentry. Server source maps are kept.
*
* Only applies to source maps the SDK generated itself. Setting `disable` to `true` or `"disable-upload"` leaves
* source map generation entirely to your Next.js config, so nothing is auto-deleted either.
* When `true`, all client source maps are deleted, also those you turned on yourself (for example with
* `productionBrowserSourceMaps`) and those that were not uploaded.
*
* Defaults to `true`.
* Defaults to `true` for webpack builds and for Turbopack builds in which the SDK turns on the client source maps.
* With `disable` set to `true` or `"disable-upload"`, nothing is deleted unless you set this option to `true`.
*/
// TODO(v12): Collapse into `filesToDeleteAfterUpload`, which already overrides this and is part of the shared
// build-time options. Two ways to express the same thing is one too many for a public API.
deleteSourcemapsAfterUpload?: boolean;
};

Expand Down
Loading
Loading