From d4e974280246012407699603eba4ccc942038c2d Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Thu, 7 Aug 2025 16:57:44 +0200 Subject: [PATCH 1/4] add flag for disabling debugid upload --- packages/bundler-plugin-core/src/index.ts | 34 ++++++++++--------- .../src/options-mapping.ts | 2 +- packages/bundler-plugin-core/src/types.ts | 2 +- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/packages/bundler-plugin-core/src/index.ts b/packages/bundler-plugin-core/src/index.ts index d382ba10..4c9c0749 100644 --- a/packages/bundler-plugin-core/src/index.ts +++ b/packages/bundler-plugin-core/src/index.ts @@ -126,22 +126,24 @@ export function sentryUnpluginFactory({ if (!options.sourcemaps?.disable) { plugins.push(debugIdInjectionPlugin(logger)); - // This option is only strongly typed for the webpack plugin, where it is used. It has no effect on other plugins - const webpack_forceExitOnBuildComplete = - typeof options._experiments["forceExitOnBuildCompletion"] === "boolean" - ? options._experiments["forceExitOnBuildCompletion"] - : undefined; - - plugins.push( - debugIdUploadPlugin( - createDebugIdUploadFunction({ - sentryBuildPluginManager, - }), - logger, - sentryBuildPluginManager.createDependencyOnBuildArtifacts, - webpack_forceExitOnBuildComplete - ) - ); + if (options.sourcemaps?.disable !== "disable-upload") { + // This option is only strongly typed for the webpack plugin, where it is used. It has no effect on other plugins + const webpack_forceExitOnBuildComplete = + typeof options._experiments["forceExitOnBuildCompletion"] === "boolean" + ? options._experiments["forceExitOnBuildCompletion"] + : undefined; + + plugins.push( + debugIdUploadPlugin( + createDebugIdUploadFunction({ + sentryBuildPluginManager, + }), + logger, + sentryBuildPluginManager.createDependencyOnBuildArtifacts, + webpack_forceExitOnBuildComplete + ) + ); + } } if (options.reactComponentAnnotation) { diff --git a/packages/bundler-plugin-core/src/options-mapping.ts b/packages/bundler-plugin-core/src/options-mapping.ts index 1ab3a532..3057c8af 100644 --- a/packages/bundler-plugin-core/src/options-mapping.ts +++ b/packages/bundler-plugin-core/src/options-mapping.ts @@ -23,7 +23,7 @@ export type NormalizedOptions = { disable: boolean; sourcemaps: | { - disable?: boolean; + disable?: boolean | "disable-upload"; assets?: string | string[]; ignore?: string | string[]; rewriteSources?: RewriteSourcesHook; diff --git a/packages/bundler-plugin-core/src/types.ts b/packages/bundler-plugin-core/src/types.ts index 1c088a4d..5232d4f4 100644 --- a/packages/bundler-plugin-core/src/types.ts +++ b/packages/bundler-plugin-core/src/types.ts @@ -95,7 +95,7 @@ export interface Options { * * Defaults to `false`. */ - disable?: boolean; + disable?: boolean | "disable-upload"; /** * A glob or an array of globs that specifies the build artifacts that should be uploaded to Sentry. From 76a08863261bb9a2381bf046dd27784374c9cdd4 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Thu, 7 Aug 2025 17:03:17 +0200 Subject: [PATCH 2/4] update api docs --- packages/bundler-plugin-core/src/types.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/bundler-plugin-core/src/types.ts b/packages/bundler-plugin-core/src/types.ts index 5232d4f4..4c5989ab 100644 --- a/packages/bundler-plugin-core/src/types.ts +++ b/packages/bundler-plugin-core/src/types.ts @@ -93,6 +93,9 @@ export interface Options { /** * Disables all functionality related to sourcemaps. * + * If set to `"disable-upload"`, the plugin will not upload sourcemaps to Sentry, but will inject debug IDs into the build artifacts. + * This is useful if you want to manually upload sourcemaps to Sentry at a later point in time. + * * Defaults to `false`. */ disable?: boolean | "disable-upload"; From cd9c272fef71efbf8b0eab0852f40950e86c4dbc Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Thu, 7 Aug 2025 18:51:45 +0200 Subject: [PATCH 3/4] tests --- packages/bundler-plugin-core/src/index.ts | 2 +- .../bundler-plugin-core/test/index.test.ts | 185 +++++++++++++++++- 2 files changed, 185 insertions(+), 2 deletions(-) diff --git a/packages/bundler-plugin-core/src/index.ts b/packages/bundler-plugin-core/src/index.ts index 4c9c0749..12bb0325 100644 --- a/packages/bundler-plugin-core/src/index.ts +++ b/packages/bundler-plugin-core/src/index.ts @@ -123,7 +123,7 @@ export function sentryUnpluginFactory({ }, }); - if (!options.sourcemaps?.disable) { + if (options.sourcemaps?.disable !== true) { plugins.push(debugIdInjectionPlugin(logger)); if (options.sourcemaps?.disable !== "disable-upload") { diff --git a/packages/bundler-plugin-core/test/index.test.ts b/packages/bundler-plugin-core/test/index.test.ts index 26087169..f6c60aa0 100644 --- a/packages/bundler-plugin-core/test/index.test.ts +++ b/packages/bundler-plugin-core/test/index.test.ts @@ -1,4 +1,5 @@ -import { getDebugIdSnippet } from "../src"; +import { Compiler } from "webpack"; +import { getDebugIdSnippet, sentryUnpluginFactory } from "../src"; describe("getDebugIdSnippet", () => { it("returns the debugId injection snippet for a passed debugId", () => { @@ -8,3 +9,185 @@ describe("getDebugIdSnippet", () => { ); }); }); + +describe("sentryUnpluginFactory sourcemaps.disable behavior", () => { + const mockReleaseInjectionPlugin = jest.fn((_injectionCode: string) => ({ + name: "mock-release-injection-plugin", + })); + + const mockComponentNameAnnotatePlugin = jest.fn(() => ({ + name: "mock-component-name-annotate-plugin", + })); + + const mockModuleMetadataInjectionPlugin = jest.fn((_injectionCode: string) => ({ + name: "mock-module-metadata-injection-plugin", + })); + + const mockDebugIdInjectionPlugin = jest.fn(() => ({ + name: "mock-debug-id-injection-plugin", + })); + + const mockDebugIdUploadPlugin = jest.fn(() => ({ + name: "mock-debug-id-upload-plugin", + })); + + const mockBundleSizeOptimizationsPlugin = jest.fn(() => ({ + name: "mock-bundle-size-optimizations-plugin", + })); + + const createUnpluginInstance = (): ReturnType => { + return sentryUnpluginFactory({ + releaseInjectionPlugin: mockReleaseInjectionPlugin, + componentNameAnnotatePlugin: mockComponentNameAnnotatePlugin, + moduleMetadataInjectionPlugin: mockModuleMetadataInjectionPlugin, + debugIdInjectionPlugin: mockDebugIdInjectionPlugin, + debugIdUploadPlugin: mockDebugIdUploadPlugin, + bundleSizeOptimizationsPlugin: mockBundleSizeOptimizationsPlugin, + }); + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe("when sourcemaps.disable is true", () => { + it("should not include debug ID injection or upload plugins", () => { + const unpluginInstance = createUnpluginInstance(); + + const plugins = unpluginInstance.raw( + { + authToken: "test-token", + org: "test-org", + project: "test-project", + sourcemaps: { + disable: true, + }, + }, + { framework: "webpack", webpack: { compiler: {} as Compiler } } + ); + + const pluginNames = plugins.map((plugin) => plugin.name); + + // Should not include debug ID related plugins + expect(pluginNames).not.toContain("mock-debug-id-injection-plugin"); + expect(pluginNames).not.toContain("mock-debug-id-upload-plugin"); + + // Should still include other core plugins + expect(pluginNames).toContain("sentry-telemetry-plugin"); + expect(pluginNames).toContain("sentry-release-management-plugin"); + expect(pluginNames).toContain("sentry-file-deletion-plugin"); + }); + }); + + describe('when sourcemaps.disable is "disable-upload"', () => { + it("should include debug ID injection plugin but not upload plugin", () => { + const unpluginInstance = createUnpluginInstance(); + + const plugins = unpluginInstance.raw( + { + authToken: "test-token", + org: "test-org", + project: "test-project", + sourcemaps: { + disable: "disable-upload", + }, + }, + { framework: "webpack", webpack: { compiler: {} as Compiler } } + ); + + const pluginNames = plugins.map((plugin) => plugin.name); + + // Should include debug ID injection but not upload + expect(pluginNames).toContain("mock-debug-id-injection-plugin"); + expect(pluginNames).not.toContain("mock-debug-id-upload-plugin"); + + // Should still include other core plugins + expect(pluginNames).toContain("sentry-telemetry-plugin"); + expect(pluginNames).toContain("sentry-release-management-plugin"); + expect(pluginNames).toContain("sentry-file-deletion-plugin"); + }); + }); + + describe("when sourcemaps.disable is false", () => { + it("should include both debug ID injection and upload plugins", () => { + const unpluginInstance = createUnpluginInstance(); + + const plugins = unpluginInstance.raw( + { + authToken: "test-token", + org: "test-org", + project: "test-project", + sourcemaps: { + disable: false, + }, + }, + { framework: "webpack", webpack: { compiler: {} as Compiler } } + ); + + const pluginNames = plugins.map((plugin) => plugin.name); + + // Should include both debug ID related plugins + expect(pluginNames).toContain("mock-debug-id-injection-plugin"); + expect(pluginNames).toContain("mock-debug-id-upload-plugin"); + + // Should include other core plugins + expect(pluginNames).toContain("sentry-telemetry-plugin"); + expect(pluginNames).toContain("sentry-release-management-plugin"); + expect(pluginNames).toContain("sentry-file-deletion-plugin"); + }); + }); + + describe("when sourcemaps.disable is undefined (default)", () => { + it("should include both debug ID injection and upload plugins", () => { + const unpluginInstance = createUnpluginInstance(); + + const plugins = unpluginInstance.raw( + { + authToken: "test-token", + org: "test-org", + project: "test-project", + // sourcemaps.disable not specified (undefined) + }, + { framework: "webpack", webpack: { compiler: {} as Compiler } } + ); + + const pluginNames = plugins.map((plugin) => plugin.name); + + // Should include both debug ID related plugins by default + expect(pluginNames).toContain("mock-debug-id-injection-plugin"); + expect(pluginNames).toContain("mock-debug-id-upload-plugin"); + + // Should include other core plugins + expect(pluginNames).toContain("sentry-telemetry-plugin"); + expect(pluginNames).toContain("sentry-release-management-plugin"); + expect(pluginNames).toContain("sentry-file-deletion-plugin"); + }); + }); + + describe("when entire sourcemaps option is undefined", () => { + it("should include both debug ID injection and upload plugins", () => { + const unpluginInstance = createUnpluginInstance(); + + const plugins = unpluginInstance.raw( + { + authToken: "test-token", + org: "test-org", + project: "test-project", + // sourcemaps option not specified at all + }, + { framework: "webpack", webpack: { compiler: {} as Compiler } } + ); + + const pluginNames = plugins.map((plugin) => plugin.name); + + // Should include both debug ID related plugins by default + expect(pluginNames).toContain("mock-debug-id-injection-plugin"); + expect(pluginNames).toContain("mock-debug-id-upload-plugin"); + + // Should include other core plugins + expect(pluginNames).toContain("sentry-telemetry-plugin"); + expect(pluginNames).toContain("sentry-release-management-plugin"); + expect(pluginNames).toContain("sentry-file-deletion-plugin"); + }); + }); +}); From 33fac405785673606f6716c9be163eb5d396709f Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Thu, 7 Aug 2025 18:52:03 +0200 Subject: [PATCH 4/4] Update packages/bundler-plugin-core/src/types.ts Co-authored-by: Lukas Stracke --- packages/bundler-plugin-core/src/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/bundler-plugin-core/src/types.ts b/packages/bundler-plugin-core/src/types.ts index 4c5989ab..0337e239 100644 --- a/packages/bundler-plugin-core/src/types.ts +++ b/packages/bundler-plugin-core/src/types.ts @@ -91,7 +91,7 @@ export interface Options { */ sourcemaps?: { /** - * Disables all functionality related to sourcemaps. + * Disables all functionality related to sourcemaps if set to `true`. * * If set to `"disable-upload"`, the plugin will not upload sourcemaps to Sentry, but will inject debug IDs into the build artifacts. * This is useful if you want to manually upload sourcemaps to Sentry at a later point in time.