From 96ebda5c06a27e514f7eb2e194d41bdf3f992550 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Fri, 16 Jan 2026 16:17:31 +0100 Subject: [PATCH 1/4] feat: Combine injection plugins --- packages/bundler-plugin-core/src/index.ts | 152 +++++++------------- packages/esbuild-plugin/src/index.ts | 8 +- packages/rollup-plugin/src/index.ts | 28 +--- packages/vite-plugin/src/index.ts | 26 +--- packages/webpack-plugin/src/webpack4and5.ts | 80 ++--------- 5 files changed, 82 insertions(+), 212 deletions(-) diff --git a/packages/bundler-plugin-core/src/index.ts b/packages/bundler-plugin-core/src/index.ts index bc350184..acd05485 100644 --- a/packages/bundler-plugin-core/src/index.ts +++ b/packages/bundler-plugin-core/src/index.ts @@ -19,11 +19,20 @@ import { stripQueryAndHashFromPath, } from "./utils"; -interface SentryUnpluginFactoryOptions { +type InjectionPlugin = ( + injectionCode: string, + debugIds: boolean, + logger: Logger +) => UnpluginOptions; +type LegacyPlugins = { releaseInjectionPlugin: (injectionCode: string) => UnpluginOptions; - componentNameAnnotatePlugin?: (ignoredComponents?: string[]) => UnpluginOptions; moduleMetadataInjectionPlugin: (injectionCode: string) => UnpluginOptions; debugIdInjectionPlugin: (logger: Logger) => UnpluginOptions; +}; + +interface SentryUnpluginFactoryOptions { + injectionPlugin: InjectionPlugin | LegacyPlugins; + componentNameAnnotatePlugin?: (ignoredComponents?: string[]) => UnpluginOptions; debugIdUploadPlugin: ( upload: (buildArtifacts: string[]) => Promise, logger: Logger, @@ -37,10 +46,8 @@ interface SentryUnpluginFactoryOptions { * Creates an unplugin instance used to create Sentry plugins for Vite, Rollup, esbuild, and Webpack. */ export function sentryUnpluginFactory({ - releaseInjectionPlugin, + injectionPlugin, componentNameAnnotatePlugin, - moduleMetadataInjectionPlugin, - debugIdInjectionPlugin, debugIdUploadPlugin, bundleSizeOptimizationsPlugin, }: SentryUnpluginFactoryOptions): UnpluginInstance { @@ -93,6 +100,8 @@ export function sentryUnpluginFactory({ plugins.push(bundleSizeOptimizationsPlugin(bundleSizeOptimizationReplacementValues)); } + let injectionCode = ""; + if (!options.release.inject) { logger.debug( "Release injection disabled via `release.inject` option. Will not inject release." @@ -102,18 +111,31 @@ export function sentryUnpluginFactory({ "No release name provided. Will not inject release. Please set the `release.name` option to identify your release." ); } else { - const injectionCode = generateGlobalInjectorCode({ + const code = generateGlobalInjectorCode({ release: options.release.name, injectBuildInformation: options._experiments.injectBuildInformation || false, }); - plugins.push(releaseInjectionPlugin(injectionCode)); + if (typeof injectionPlugin !== "function") { + plugins.push(injectionPlugin.releaseInjectionPlugin(code)); + } else { + injectionCode += code; + } } if (Object.keys(sentryBuildPluginManager.bundleMetadata).length > 0) { - const injectionCode = generateModuleMetadataInjectorCode( - sentryBuildPluginManager.bundleMetadata - ); - plugins.push(moduleMetadataInjectionPlugin(injectionCode)); + const code = generateModuleMetadataInjectorCode(sentryBuildPluginManager.bundleMetadata); + if (typeof injectionPlugin !== "function") { + plugins.push(injectionPlugin.moduleMetadataInjectionPlugin(code)); + } else { + injectionCode += code; + } + } + + if ( + typeof injectionPlugin === "function" && + (injectionCode !== "" || options.sourcemaps?.disable !== true) + ) { + plugins.push(injectionPlugin(injectionCode, options.sourcemaps?.disable !== true, logger)); } // Add plugin to create and finalize releases, and also take care of adding commits and legacy sourcemaps @@ -131,7 +153,9 @@ export function sentryUnpluginFactory({ }); if (options.sourcemaps?.disable !== true) { - plugins.push(debugIdInjectionPlugin(logger)); + if (typeof injectionPlugin !== "function") { + plugins.push(injectionPlugin.debugIdInjectionPlugin(logger)); + } 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 @@ -248,42 +272,6 @@ function shouldSkipCodeInjection(code: string, facadeModuleId: string | null | u return false; } -export function createRollupReleaseInjectionHooks(injectionCode: string): { - renderChunk: RenderChunkHook; -} { - return { - renderChunk(code: string, chunk: { fileName: string; facadeModuleId?: string | null }) { - if (!isJsFile(chunk.fileName)) { - return null; // returning null means not modifying the chunk at all - } - - // Skip empty chunks and HTML facade chunks (Vite MPA) - if (shouldSkipCodeInjection(code, chunk.facadeModuleId)) { - return null; - } - - const ms = new MagicString(code, { filename: chunk.fileName }); - - const match = code.match(COMMENT_USE_STRICT_REGEX)?.[0]; - - if (match) { - // Add injected code after any comments or "use strict" at the beginning of the bundle. - ms.appendLeft(match.length, injectionCode); - } else { - // ms.replace() doesn't work when there is an empty string match (which happens if - // there is neither, a comment, nor a "use strict" at the top of the chunk) so we - // need this special case here. - ms.prepend(injectionCode); - } - - return { - code: ms.toString(), - map: ms.generateMap({ file: chunk.fileName, hires: "boundary" }), - }; - }, - }; -} - export function createRollupBundleSizeOptimizationHooks(replacementValues: SentrySDKBuildFlags): { transform: UnpluginOptions["transform"]; } { @@ -294,7 +282,10 @@ export function createRollupBundleSizeOptimizationHooks(replacementValues: Sentr }; } -export function createRollupDebugIdInjectionHooks(): { +export function createRollupInjectionHooks( + injectionCode: string, + debugIds: boolean +): { renderChunk: RenderChunkHook; } { return { @@ -308,68 +299,35 @@ export function createRollupDebugIdInjectionHooks(): { return null; } - // Check if a debug ID has already been injected to avoid duplicate injection (e.g. by another plugin or Sentry CLI) - const chunkStartSnippet = code.slice(0, 6000); - const chunkEndSnippet = code.slice(-500); - - if ( - chunkStartSnippet.includes("_sentryDebugIdIdentifier") || - chunkEndSnippet.includes("//# debugId=") - ) { - return null; // Debug ID already present, skip injection - } - - const debugId = stringToUUID(code); // generate a deterministic debug ID - const codeToInject = getDebugIdSnippet(debugId); - - const ms = new MagicString(code, { filename: chunk.fileName }); - - const match = code.match(COMMENT_USE_STRICT_REGEX)?.[0]; + let codeToInject = injectionCode; - if (match) { - // Add injected code after any comments or "use strict" at the beginning of the bundle. - ms.appendLeft(match.length, codeToInject); - } else { - // ms.replace() doesn't work when there is an empty string match (which happens if - // there is neither, a comment, nor a "use strict" at the top of the chunk) so we - // need this special case here. - ms.prepend(codeToInject); - } + if (debugIds) { + // Check if a debug ID has already been injected to avoid duplicate injection (e.g. by another plugin or Sentry CLI) + const chunkStartSnippet = code.slice(0, 6000); + const chunkEndSnippet = code.slice(-500); - return { - code: ms.toString(), - map: ms.generateMap({ file: chunk.fileName, hires: "boundary" }), - }; - }, - }; -} - -export function createRollupModuleMetadataInjectionHooks(injectionCode: string): { - renderChunk: RenderChunkHook; -} { - return { - renderChunk(code: string, chunk: { fileName: string; facadeModuleId?: string | null }) { - if (!isJsFile(chunk.fileName)) { - return null; // returning null means not modifying the chunk at all - } + if ( + chunkStartSnippet.includes("_sentryDebugIdIdentifier") || + chunkEndSnippet.includes("//# debugId=") + ) { + return null; // Debug ID already present, skip injection + } - // Skip empty chunks and HTML facade chunks (Vite MPA) - if (shouldSkipCodeInjection(code, chunk.facadeModuleId)) { - return null; + const debugId = stringToUUID(code); // generate a deterministic debug ID + codeToInject += getDebugIdSnippet(debugId); } const ms = new MagicString(code, { filename: chunk.fileName }); - const match = code.match(COMMENT_USE_STRICT_REGEX)?.[0]; if (match) { // Add injected code after any comments or "use strict" at the beginning of the bundle. - ms.appendLeft(match.length, injectionCode); + ms.appendLeft(match.length, codeToInject); } else { // ms.replace() doesn't work when there is an empty string match (which happens if // there is neither, a comment, nor a "use strict" at the top of the chunk) so we // need this special case here. - ms.prepend(injectionCode); + ms.prepend(codeToInject); } return { diff --git a/packages/esbuild-plugin/src/index.ts b/packages/esbuild-plugin/src/index.ts index 29918afa..4b2e8270 100644 --- a/packages/esbuild-plugin/src/index.ts +++ b/packages/esbuild-plugin/src/index.ts @@ -317,9 +317,11 @@ function esbuildBundleSizeOptimizationsPlugin( } const sentryUnplugin = sentryUnpluginFactory({ - releaseInjectionPlugin: esbuildReleaseInjectionPlugin, - debugIdInjectionPlugin: esbuildDebugIdInjectionPlugin, - moduleMetadataInjectionPlugin: esbuildModuleMetadataInjectionPlugin, + injectionPlugin: { + releaseInjectionPlugin: esbuildReleaseInjectionPlugin, + debugIdInjectionPlugin: esbuildDebugIdInjectionPlugin, + moduleMetadataInjectionPlugin: esbuildModuleMetadataInjectionPlugin, + }, debugIdUploadPlugin: esbuildDebugIdUploadPlugin, bundleSizeOptimizationsPlugin: esbuildBundleSizeOptimizationsPlugin, }); diff --git a/packages/rollup-plugin/src/index.ts b/packages/rollup-plugin/src/index.ts index 6ca2466f..30ad55fd 100644 --- a/packages/rollup-plugin/src/index.ts +++ b/packages/rollup-plugin/src/index.ts @@ -1,9 +1,7 @@ import { sentryUnpluginFactory, Options, - createRollupReleaseInjectionHooks, - createRollupModuleMetadataInjectionHooks, - createRollupDebugIdInjectionHooks, + createRollupInjectionHooks, createRollupDebugIdUploadHooks, SentrySDKBuildFlags, createRollupBundleSizeOptimizationHooks, @@ -12,13 +10,6 @@ import { } from "@sentry/bundler-plugin-core"; import type { UnpluginOptions } from "unplugin"; -function rollupReleaseInjectionPlugin(injectionCode: string): UnpluginOptions { - return { - name: "sentry-rollup-release-injection-plugin", - rollup: createRollupReleaseInjectionHooks(injectionCode), - }; -} - function rollupComponentNameAnnotatePlugin(ignoredComponents?: string[]): UnpluginOptions { return { name: "sentry-rollup-component-name-annotate-plugin", @@ -26,17 +17,10 @@ function rollupComponentNameAnnotatePlugin(ignoredComponents?: string[]): Unplug }; } -function rollupDebugIdInjectionPlugin(): UnpluginOptions { - return { - name: "sentry-rollup-debug-id-injection-plugin", - rollup: createRollupDebugIdInjectionHooks(), - }; -} - -function rollupModuleMetadataInjectionPlugin(injectionCode: string): UnpluginOptions { +function rollupInjectionPlugin(injectionCode: string, debugIds: boolean): UnpluginOptions { return { - name: "sentry-rollup-module-metadata-injection-plugin", - rollup: createRollupModuleMetadataInjectionHooks(injectionCode), + name: "sentry-rollup-injection-plugin", + rollup: createRollupInjectionHooks(injectionCode, debugIds), }; } @@ -61,10 +45,8 @@ function rollupBundleSizeOptimizationsPlugin( } const sentryUnplugin = sentryUnpluginFactory({ - releaseInjectionPlugin: rollupReleaseInjectionPlugin, + injectionPlugin: rollupInjectionPlugin, componentNameAnnotatePlugin: rollupComponentNameAnnotatePlugin, - debugIdInjectionPlugin: rollupDebugIdInjectionPlugin, - moduleMetadataInjectionPlugin: rollupModuleMetadataInjectionPlugin, debugIdUploadPlugin: rollupDebugIdUploadPlugin, bundleSizeOptimizationsPlugin: rollupBundleSizeOptimizationsPlugin, }); diff --git a/packages/vite-plugin/src/index.ts b/packages/vite-plugin/src/index.ts index 2c460f8b..8b5e308b 100644 --- a/packages/vite-plugin/src/index.ts +++ b/packages/vite-plugin/src/index.ts @@ -1,9 +1,7 @@ import { sentryUnpluginFactory, Options, - createRollupReleaseInjectionHooks, - createRollupModuleMetadataInjectionHooks, - createRollupDebugIdInjectionHooks, + createRollupInjectionHooks, createRollupDebugIdUploadHooks, SentrySDKBuildFlags, createRollupBundleSizeOptimizationHooks, @@ -12,13 +10,13 @@ import { } from "@sentry/bundler-plugin-core"; import { UnpluginOptions, VitePlugin } from "unplugin"; -function viteReleaseInjectionPlugin(injectionCode: string): UnpluginOptions { +function viteInjectionPlugin(injectionCode: string, debugIds: boolean): UnpluginOptions { return { name: "sentry-vite-release-injection-plugin", // run `post` to avoid tripping up @rollup/plugin-commonjs when cjs is used // as we inject an `import` statement enforce: "post" as const, // need this so that vite runs the resolveId hook - vite: createRollupReleaseInjectionHooks(injectionCode), + vite: createRollupInjectionHooks(injectionCode, debugIds), }; } @@ -30,20 +28,6 @@ function viteComponentNameAnnotatePlugin(ignoredComponents?: string[]): Unplugin }; } -function viteDebugIdInjectionPlugin(): UnpluginOptions { - return { - name: "sentry-vite-debug-id-injection-plugin", - vite: createRollupDebugIdInjectionHooks(), - }; -} - -function viteModuleMetadataInjectionPlugin(injectionCode: string): UnpluginOptions { - return { - name: "sentry-vite-module-metadata-injection-plugin", - vite: createRollupModuleMetadataInjectionHooks(injectionCode), - }; -} - function viteDebugIdUploadPlugin( upload: (buildArtifacts: string[]) => Promise, logger: Logger, @@ -65,10 +49,8 @@ function viteBundleSizeOptimizationsPlugin( } const sentryUnplugin = sentryUnpluginFactory({ - releaseInjectionPlugin: viteReleaseInjectionPlugin, + injectionPlugin: viteInjectionPlugin, componentNameAnnotatePlugin: viteComponentNameAnnotatePlugin, - debugIdInjectionPlugin: viteDebugIdInjectionPlugin, - moduleMetadataInjectionPlugin: viteModuleMetadataInjectionPlugin, debugIdUploadPlugin: viteDebugIdUploadPlugin, bundleSizeOptimizationsPlugin: viteBundleSizeOptimizationsPlugin, }); diff --git a/packages/webpack-plugin/src/webpack4and5.ts b/packages/webpack-plugin/src/webpack4and5.ts index 5c7c3e29..d8838356 100644 --- a/packages/webpack-plugin/src/webpack4and5.ts +++ b/packages/webpack-plugin/src/webpack4and5.ts @@ -33,10 +33,10 @@ type UnsafeDefinePlugin = { new (options: any): unknown; }; -function webpackReleaseInjectionPlugin( +function webpackInjectionPlugin( UnsafeBannerPlugin: UnsafeBannerPlugin | undefined -): (injectionCode: string) => UnpluginOptions { - return (injectionCode: string): UnpluginOptions => ({ +): (injectionCode: string, debugIds: boolean) => UnpluginOptions { + return (injectionCode: string, debugIds: boolean): UnpluginOptions => ({ name: "sentry-webpack-release-injection-plugin", webpack(compiler) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment @@ -54,7 +54,15 @@ function webpackReleaseInjectionPlugin( new BannerPlugin({ raw: true, include: /\.(js|ts|jsx|tsx|mjs|cjs)(\?[^?]*)?(#[^#]*)?$/, - banner: injectionCode, + banner: (arg?: BannerPluginCallbackArg) => { + let codeToInject = injectionCode; + if (debugIds) { + const hash = arg?.chunk?.contentHash?.javascript ?? arg?.chunk?.hash; + const debugId = hash ? stringToUUID(hash) : uuidv4(); + codeToInject += getDebugIdSnippet(debugId); + } + return codeToInject; + }, }) ); }, @@ -99,38 +107,6 @@ function webpackBundleSizeOptimizationsPlugin( }); } -function webpackDebugIdInjectionPlugin( - UnsafeBannerPlugin: UnsafeBannerPlugin | undefined -): () => UnpluginOptions { - return () => ({ - name: "sentry-webpack-debug-id-injection-plugin", - webpack(compiler) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore webpack version compatibility shenanigans - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access - const BannerPlugin = - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore webpack version compatibility shenanigans - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - compiler?.webpack?.BannerPlugin || UnsafeBannerPlugin; - - compiler.options.plugins = compiler.options.plugins || []; - compiler.options.plugins.push( - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call - new BannerPlugin({ - raw: true, - include: /\.(js|ts|jsx|tsx|mjs|cjs)(\?[^?]*)?(#[^#]*)?$/, - banner: (arg?: BannerPluginCallbackArg) => { - const hash = arg?.chunk?.contentHash?.javascript ?? arg?.chunk?.hash; - const debugId = hash ? stringToUUID(hash) : uuidv4(); - return getDebugIdSnippet(debugId); - }, - }) - ); - }, - }); -} - function webpackDebugIdUploadPlugin( upload: (buildArtifacts: string[]) => Promise, logger: Logger, @@ -170,34 +146,6 @@ function webpackDebugIdUploadPlugin( }; } -function webpackModuleMetadataInjectionPlugin( - UnsafeBannerPlugin: UnsafeBannerPlugin | undefined -): (injectionCode: string) => UnpluginOptions { - return (injectionCode: string) => ({ - name: "sentry-webpack-module-metadata-injection-plugin", - webpack(compiler) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore webpack version compatibility shenanigans - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access - const BannerPlugin = - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore webpack version compatibility shenanigans - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - compiler?.webpack?.BannerPlugin || UnsafeBannerPlugin; - - compiler.options.plugins = compiler.options.plugins || []; - compiler.options.plugins.push( - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call - new BannerPlugin({ - raw: true, - include: /\.(js|ts|jsx|tsx|mjs|cjs)(\?[^?]*)?(#[^#]*)?$/, - banner: injectionCode, - }) - ); - }, - }); -} - /** * The factory function accepts BannerPlugin and DefinePlugin classes in * order to avoid direct dependencies on webpack. @@ -214,10 +162,8 @@ export function sentryWebpackUnpluginFactory({ DefinePlugin?: UnsafeDefinePlugin; } = {}): ReturnType { return sentryUnpluginFactory({ - releaseInjectionPlugin: webpackReleaseInjectionPlugin(BannerPlugin), + injectionPlugin: webpackInjectionPlugin(BannerPlugin), componentNameAnnotatePlugin: webpackComponentNameAnnotatePlugin(), - moduleMetadataInjectionPlugin: webpackModuleMetadataInjectionPlugin(BannerPlugin), - debugIdInjectionPlugin: webpackDebugIdInjectionPlugin(BannerPlugin), debugIdUploadPlugin: webpackDebugIdUploadPlugin, bundleSizeOptimizationsPlugin: webpackBundleSizeOptimizationsPlugin(DefinePlugin), }); From d590e21172819f22c4bc591d81e6190afa9febf5 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Fri, 16 Jan 2026 16:23:52 +0100 Subject: [PATCH 2/4] Fix tests --- .../bundler-plugin-core/test/index.test.ts | 36 +++++++------------ .../rollup-plugin/test/public-api.test.ts | 3 +- packages/vite-plugin/src/index.ts | 2 +- packages/vite-plugin/test/public-api.test.ts | 3 +- 4 files changed, 16 insertions(+), 28 deletions(-) diff --git a/packages/bundler-plugin-core/test/index.test.ts b/packages/bundler-plugin-core/test/index.test.ts index 9c69694e..62f7d752 100644 --- a/packages/bundler-plugin-core/test/index.test.ts +++ b/packages/bundler-plugin-core/test/index.test.ts @@ -2,7 +2,7 @@ import { Compiler } from "webpack"; import { getDebugIdSnippet, sentryUnpluginFactory, - createRollupDebugIdInjectionHooks, + createRollupInjectionHooks, } from "../src"; describe("getDebugIdSnippet", () => { @@ -14,8 +14,8 @@ describe("getDebugIdSnippet", () => { }); }); -describe("createRollupDebugIdInjectionHooks", () => { - const hooks = createRollupDebugIdInjectionHooks(); +describe("createRollupInjectionHooks", () => { + const hooks = createRollupInjectionHooks('', true); describe("renderChunk", () => { it("should inject debug ID into clean JavaScript files", () => { @@ -74,9 +74,9 @@ describe("createRollupDebugIdInjectionHooks", () => { [ "inline format with large file", '"use strict";\n' + - "// comment\n".repeat(10) + - ';{try{(function(){var e="undefined"!=typeof window?window:e._sentryDebugIdIdentifier="sentry-dbid-existing-id");})();}catch(e){}};' + - '\nconsole.log("line");\n'.repeat(100), + "// comment\n".repeat(10) + + ';{try{(function(){var e="undefined"!=typeof window?window:e._sentryDebugIdIdentifier="sentry-dbid-existing-id");})();}catch(e){}};' + + '\nconsole.log("line");\n'.repeat(100), ], ])("should NOT inject when debug ID already exists (%s)", (_description, code) => { const result = hooks.renderChunk(code, { fileName: "bundle.js" }); @@ -103,20 +103,12 @@ describe("createRollupDebugIdInjectionHooks", () => { }); 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 mockInjectionPlugin = jest.fn(() => ({ + name: "mock-injection-plugin", })); const mockDebugIdUploadPlugin = jest.fn(() => ({ @@ -129,10 +121,8 @@ describe("sentryUnpluginFactory sourcemaps.disable behavior", () => { const createUnpluginInstance = (): ReturnType => { return sentryUnpluginFactory({ - releaseInjectionPlugin: mockReleaseInjectionPlugin, + injectionPlugin: mockInjectionPlugin, componentNameAnnotatePlugin: mockComponentNameAnnotatePlugin, - moduleMetadataInjectionPlugin: mockModuleMetadataInjectionPlugin, - debugIdInjectionPlugin: mockDebugIdInjectionPlugin, debugIdUploadPlugin: mockDebugIdUploadPlugin, bundleSizeOptimizationsPlugin: mockBundleSizeOptimizationsPlugin, }); @@ -190,7 +180,7 @@ describe("sentryUnpluginFactory sourcemaps.disable behavior", () => { 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).toContain("mock-injection-plugin"); expect(pluginNames).not.toContain("mock-debug-id-upload-plugin"); // Should still include other core plugins @@ -219,7 +209,7 @@ describe("sentryUnpluginFactory sourcemaps.disable behavior", () => { 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-injection-plugin"); expect(pluginNames).toContain("mock-debug-id-upload-plugin"); // Should include other core plugins @@ -246,7 +236,7 @@ describe("sentryUnpluginFactory sourcemaps.disable behavior", () => { 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-injection-plugin"); expect(pluginNames).toContain("mock-debug-id-upload-plugin"); // Should include other core plugins @@ -273,7 +263,7 @@ describe("sentryUnpluginFactory sourcemaps.disable behavior", () => { 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-injection-plugin"); expect(pluginNames).toContain("mock-debug-id-upload-plugin"); // Should include other core plugins diff --git a/packages/rollup-plugin/test/public-api.test.ts b/packages/rollup-plugin/test/public-api.test.ts index 8a36177c..ced22fbc 100644 --- a/packages/rollup-plugin/test/public-api.test.ts +++ b/packages/rollup-plugin/test/public-api.test.ts @@ -25,9 +25,8 @@ describe("sentryRollupPlugin", () => { expect(pluginNames).toEqual( expect.arrayContaining([ "sentry-telemetry-plugin", - "sentry-rollup-release-injection-plugin", "sentry-release-management-plugin", - "sentry-rollup-debug-id-injection-plugin", + "sentry-rollup-injection-plugin", "sentry-rollup-debug-id-upload-plugin", "sentry-file-deletion-plugin", ]) diff --git a/packages/vite-plugin/src/index.ts b/packages/vite-plugin/src/index.ts index 8b5e308b..a6bc4ac7 100644 --- a/packages/vite-plugin/src/index.ts +++ b/packages/vite-plugin/src/index.ts @@ -12,7 +12,7 @@ import { UnpluginOptions, VitePlugin } from "unplugin"; function viteInjectionPlugin(injectionCode: string, debugIds: boolean): UnpluginOptions { return { - name: "sentry-vite-release-injection-plugin", + name: "sentry-vite-injection-plugin", // run `post` to avoid tripping up @rollup/plugin-commonjs when cjs is used // as we inject an `import` statement enforce: "post" as const, // need this so that vite runs the resolveId hook diff --git a/packages/vite-plugin/test/public-api.test.ts b/packages/vite-plugin/test/public-api.test.ts index 8c311783..bd0d0827 100644 --- a/packages/vite-plugin/test/public-api.test.ts +++ b/packages/vite-plugin/test/public-api.test.ts @@ -24,9 +24,8 @@ describe("sentryVitePlugin", () => { expect(pluginNames).toEqual( expect.arrayContaining([ "sentry-telemetry-plugin", - "sentry-vite-release-injection-plugin", "sentry-release-management-plugin", - "sentry-vite-debug-id-injection-plugin", + "sentry-vite-injection-plugin", "sentry-vite-debug-id-upload-plugin", "sentry-file-deletion-plugin", ]) From f964e394eacd86ad18d56399b649548a5426eb21 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Fri, 16 Jan 2026 17:00:29 +0100 Subject: [PATCH 3/4] Fix lint --- packages/bundler-plugin-core/src/index.ts | 12 ++++++------ packages/bundler-plugin-core/test/index.test.ts | 14 +++++--------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/packages/bundler-plugin-core/src/index.ts b/packages/bundler-plugin-core/src/index.ts index acd05485..4746d0cf 100644 --- a/packages/bundler-plugin-core/src/index.ts +++ b/packages/bundler-plugin-core/src/index.ts @@ -307,14 +307,14 @@ export function createRollupInjectionHooks( const chunkEndSnippet = code.slice(-500); if ( - chunkStartSnippet.includes("_sentryDebugIdIdentifier") || - chunkEndSnippet.includes("//# debugId=") + !( + chunkStartSnippet.includes("_sentryDebugIdIdentifier") || + chunkEndSnippet.includes("//# debugId=") + ) ) { - return null; // Debug ID already present, skip injection + const debugId = stringToUUID(code); // generate a deterministic debug ID + codeToInject += getDebugIdSnippet(debugId); } - - const debugId = stringToUUID(code); // generate a deterministic debug ID - codeToInject += getDebugIdSnippet(debugId); } const ms = new MagicString(code, { filename: chunk.fileName }); diff --git a/packages/bundler-plugin-core/test/index.test.ts b/packages/bundler-plugin-core/test/index.test.ts index 62f7d752..047dc37d 100644 --- a/packages/bundler-plugin-core/test/index.test.ts +++ b/packages/bundler-plugin-core/test/index.test.ts @@ -1,9 +1,5 @@ import { Compiler } from "webpack"; -import { - getDebugIdSnippet, - sentryUnpluginFactory, - createRollupInjectionHooks, -} from "../src"; +import { getDebugIdSnippet, sentryUnpluginFactory, createRollupInjectionHooks } from "../src"; describe("getDebugIdSnippet", () => { it("returns the debugId injection snippet for a passed debugId", () => { @@ -15,7 +11,7 @@ describe("getDebugIdSnippet", () => { }); describe("createRollupInjectionHooks", () => { - const hooks = createRollupInjectionHooks('', true); + const hooks = createRollupInjectionHooks("", true); describe("renderChunk", () => { it("should inject debug ID into clean JavaScript files", () => { @@ -74,9 +70,9 @@ describe("createRollupInjectionHooks", () => { [ "inline format with large file", '"use strict";\n' + - "// comment\n".repeat(10) + - ';{try{(function(){var e="undefined"!=typeof window?window:e._sentryDebugIdIdentifier="sentry-dbid-existing-id");})();}catch(e){}};' + - '\nconsole.log("line");\n'.repeat(100), + "// comment\n".repeat(10) + + ';{try{(function(){var e="undefined"!=typeof window?window:e._sentryDebugIdIdentifier="sentry-dbid-existing-id");})();}catch(e){}};' + + '\nconsole.log("line");\n'.repeat(100), ], ])("should NOT inject when debug ID already exists (%s)", (_description, code) => { const result = hooks.renderChunk(code, { fileName: "bundle.js" }); From 96d56ff021d23f0eccd3ca7aa10abbb2163ea8ff Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Fri, 16 Jan 2026 17:06:31 +0100 Subject: [PATCH 4/4] Fix lint --- packages/bundler-plugin-core/test/index.test.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/bundler-plugin-core/test/index.test.ts b/packages/bundler-plugin-core/test/index.test.ts index be524055..e9babd0b 100644 --- a/packages/bundler-plugin-core/test/index.test.ts +++ b/packages/bundler-plugin-core/test/index.test.ts @@ -1,9 +1,5 @@ import { Compiler } from "webpack"; -import { - getDebugIdSnippet, - sentryUnpluginFactory, - createRollupInjectionHooks, -} from "../src"; +import { getDebugIdSnippet, sentryUnpluginFactory, createRollupInjectionHooks } from "../src"; import { containsOnlyImports } from "../src/utils"; describe("getDebugIdSnippet", () => { @@ -206,13 +202,13 @@ describe("createRollupInjectionHooks", () => { [ "inline format with large file", '"use strict";\n' + - "// comment\n".repeat(10) + - ';{try{(function(){var e="undefined"!=typeof window?window:e._sentryDebugIdIdentifier="sentry-dbid-existing-id");})();}catch(e){}};' + - '\nconsole.log("line");\n'.repeat(100), + "// comment\n".repeat(10) + + ';{try{(function(){var e="undefined"!=typeof window?window:e._sentryDebugIdIdentifier="sentry-dbid-existing-id");})();}catch(e){}};' + + '\nconsole.log("line");\n'.repeat(100), ], ])("should NOT inject when debug ID already exists (%s)", (_description, code) => { const result = hooks.renderChunk(code, { fileName: "bundle.js" }); - expect(result).toBeNull(); + expect(result?.code).not.toContain("_sentryDebugIds"); }); it("should only check boundaries for performance (not entire file)", () => {