@@ -20,11 +20,20 @@ import {
2020 stripQueryAndHashFromPath ,
2121} from "./utils" ;
2222
23- interface SentryUnpluginFactoryOptions {
23+ type InjectionPlugin = (
24+ injectionCode : string ,
25+ debugIds : boolean ,
26+ logger : Logger
27+ ) => UnpluginOptions ;
28+ type LegacyPlugins = {
2429 releaseInjectionPlugin : ( injectionCode : string ) => UnpluginOptions ;
25- componentNameAnnotatePlugin ?: ( ignoredComponents ?: string [ ] ) => UnpluginOptions ;
2630 moduleMetadataInjectionPlugin : ( injectionCode : string ) => UnpluginOptions ;
2731 debugIdInjectionPlugin : ( logger : Logger ) => UnpluginOptions ;
32+ } ;
33+
34+ interface SentryUnpluginFactoryOptions {
35+ injectionPlugin : InjectionPlugin | LegacyPlugins ;
36+ componentNameAnnotatePlugin ?: ( ignoredComponents ?: string [ ] ) => UnpluginOptions ;
2837 debugIdUploadPlugin : (
2938 upload : ( buildArtifacts : string [ ] ) => Promise < void > ,
3039 logger : Logger ,
@@ -38,10 +47,8 @@ interface SentryUnpluginFactoryOptions {
3847 * Creates an unplugin instance used to create Sentry plugins for Vite, Rollup, esbuild, and Webpack.
3948 */
4049export function sentryUnpluginFactory ( {
41- releaseInjectionPlugin ,
50+ injectionPlugin ,
4251 componentNameAnnotatePlugin,
43- moduleMetadataInjectionPlugin,
44- debugIdInjectionPlugin,
4552 debugIdUploadPlugin,
4653 bundleSizeOptimizationsPlugin,
4754} : SentryUnpluginFactoryOptions ) : UnpluginInstance < Options | undefined , true > {
@@ -94,6 +101,8 @@ export function sentryUnpluginFactory({
94101 plugins . push ( bundleSizeOptimizationsPlugin ( bundleSizeOptimizationReplacementValues ) ) ;
95102 }
96103
104+ let injectionCode = "" ;
105+
97106 if ( ! options . release . inject ) {
98107 logger . debug (
99108 "Release injection disabled via `release.inject` option. Will not inject release."
@@ -103,18 +112,31 @@ export function sentryUnpluginFactory({
103112 "No release name provided. Will not inject release. Please set the `release.name` option to identify your release."
104113 ) ;
105114 } else {
106- const injectionCode = generateGlobalInjectorCode ( {
115+ const code = generateGlobalInjectorCode ( {
107116 release : options . release . name ,
108117 injectBuildInformation : options . _experiments . injectBuildInformation || false ,
109118 } ) ;
110- plugins . push ( releaseInjectionPlugin ( injectionCode ) ) ;
119+ if ( typeof injectionPlugin !== "function" ) {
120+ plugins . push ( injectionPlugin . releaseInjectionPlugin ( code ) ) ;
121+ } else {
122+ injectionCode += code ;
123+ }
111124 }
112125
113126 if ( Object . keys ( sentryBuildPluginManager . bundleMetadata ) . length > 0 ) {
114- const injectionCode = generateModuleMetadataInjectorCode (
115- sentryBuildPluginManager . bundleMetadata
116- ) ;
117- plugins . push ( moduleMetadataInjectionPlugin ( injectionCode ) ) ;
127+ const code = generateModuleMetadataInjectorCode ( sentryBuildPluginManager . bundleMetadata ) ;
128+ if ( typeof injectionPlugin !== "function" ) {
129+ plugins . push ( injectionPlugin . moduleMetadataInjectionPlugin ( code ) ) ;
130+ } else {
131+ injectionCode += code ;
132+ }
133+ }
134+
135+ if (
136+ typeof injectionPlugin === "function" &&
137+ ( injectionCode !== "" || options . sourcemaps ?. disable !== true )
138+ ) {
139+ plugins . push ( injectionPlugin ( injectionCode , options . sourcemaps ?. disable !== true , logger ) ) ;
118140 }
119141
120142 // Add plugin to create and finalize releases, and also take care of adding commits and legacy sourcemaps
@@ -132,7 +154,9 @@ export function sentryUnpluginFactory({
132154 } ) ;
133155
134156 if ( options . sourcemaps ?. disable !== true ) {
135- plugins . push ( debugIdInjectionPlugin ( logger ) ) ;
157+ if ( typeof injectionPlugin !== "function" ) {
158+ plugins . push ( injectionPlugin . debugIdInjectionPlugin ( logger ) ) ;
159+ }
136160
137161 if ( options . sourcemaps ?. disable !== "disable-upload" ) {
138162 // This option is only strongly typed for the webpack plugin, where it is used. It has no effect on other plugins
@@ -251,42 +275,6 @@ function shouldSkipCodeInjection(code: string, facadeModuleId: string | null | u
251275 return false ;
252276}
253277
254- export function createRollupReleaseInjectionHooks ( injectionCode : string ) : {
255- renderChunk : RenderChunkHook ;
256- } {
257- return {
258- renderChunk ( code : string , chunk : { fileName : string ; facadeModuleId ?: string | null } ) {
259- if ( ! isJsFile ( chunk . fileName ) ) {
260- return null ; // returning null means not modifying the chunk at all
261- }
262-
263- // Skip empty chunks and HTML facade chunks (Vite MPA)
264- if ( shouldSkipCodeInjection ( code , chunk . facadeModuleId ) ) {
265- return null ;
266- }
267-
268- const ms = new MagicString ( code , { filename : chunk . fileName } ) ;
269-
270- const match = code . match ( COMMENT_USE_STRICT_REGEX ) ?. [ 0 ] ;
271-
272- if ( match ) {
273- // Add injected code after any comments or "use strict" at the beginning of the bundle.
274- ms . appendLeft ( match . length , injectionCode ) ;
275- } else {
276- // ms.replace() doesn't work when there is an empty string match (which happens if
277- // there is neither, a comment, nor a "use strict" at the top of the chunk) so we
278- // need this special case here.
279- ms . prepend ( injectionCode ) ;
280- }
281-
282- return {
283- code : ms . toString ( ) ,
284- map : ms . generateMap ( { file : chunk . fileName , hires : "boundary" } ) ,
285- } ;
286- } ,
287- } ;
288- }
289-
290278export function createRollupBundleSizeOptimizationHooks ( replacementValues : SentrySDKBuildFlags ) : {
291279 transform : UnpluginOptions [ "transform" ] ;
292280} {
@@ -297,7 +285,10 @@ export function createRollupBundleSizeOptimizationHooks(replacementValues: Sentr
297285 } ;
298286}
299287
300- export function createRollupDebugIdInjectionHooks ( ) : {
288+ export function createRollupInjectionHooks (
289+ injectionCode : string ,
290+ debugIds : boolean
291+ ) : {
301292 renderChunk : RenderChunkHook ;
302293} {
303294 return {
@@ -311,22 +302,25 @@ export function createRollupDebugIdInjectionHooks(): {
311302 return null ;
312303 }
313304
314- // Check if a debug ID has already been injected to avoid duplicate injection (e.g. by another plugin or Sentry CLI)
315- const chunkStartSnippet = code . slice ( 0 , 6000 ) ;
316- const chunkEndSnippet = code . slice ( - 500 ) ;
305+ let codeToInject = injectionCode ;
317306
318- if (
319- chunkStartSnippet . includes ( "_sentryDebugIdIdentifier" ) ||
320- chunkEndSnippet . includes ( "//# debugId=" )
321- ) {
322- return null ; // Debug ID already present, skip injection
323- }
307+ if ( debugIds ) {
308+ // Check if a debug ID has already been injected to avoid duplicate injection (e.g. by another plugin or Sentry CLI)
309+ const chunkStartSnippet = code . slice ( 0 , 6000 ) ;
310+ const chunkEndSnippet = code . slice ( - 500 ) ;
324311
325- const debugId = stringToUUID ( code ) ; // generate a deterministic debug ID
326- const codeToInject = getDebugIdSnippet ( debugId ) ;
312+ if (
313+ ! (
314+ chunkStartSnippet . includes ( "_sentryDebugIdIdentifier" ) ||
315+ chunkEndSnippet . includes ( "//# debugId=" )
316+ )
317+ ) {
318+ const debugId = stringToUUID ( code ) ; // generate a deterministic debug ID
319+ codeToInject += getDebugIdSnippet ( debugId ) ;
320+ }
321+ }
327322
328323 const ms = new MagicString ( code , { filename : chunk . fileName } ) ;
329-
330324 const match = code . match ( COMMENT_USE_STRICT_REGEX ) ?. [ 0 ] ;
331325
332326 if ( match ) {
@@ -347,42 +341,6 @@ export function createRollupDebugIdInjectionHooks(): {
347341 } ;
348342}
349343
350- export function createRollupModuleMetadataInjectionHooks ( injectionCode : string ) : {
351- renderChunk : RenderChunkHook ;
352- } {
353- return {
354- renderChunk ( code : string , chunk : { fileName : string ; facadeModuleId ?: string | null } ) {
355- if ( ! isJsFile ( chunk . fileName ) ) {
356- return null ; // returning null means not modifying the chunk at all
357- }
358-
359- // Skip empty chunks and HTML facade chunks (Vite MPA)
360- if ( shouldSkipCodeInjection ( code , chunk . facadeModuleId ) ) {
361- return null ;
362- }
363-
364- const ms = new MagicString ( code , { filename : chunk . fileName } ) ;
365-
366- const match = code . match ( COMMENT_USE_STRICT_REGEX ) ?. [ 0 ] ;
367-
368- if ( match ) {
369- // Add injected code after any comments or "use strict" at the beginning of the bundle.
370- ms . appendLeft ( match . length , injectionCode ) ;
371- } else {
372- // ms.replace() doesn't work when there is an empty string match (which happens if
373- // there is neither, a comment, nor a "use strict" at the top of the chunk) so we
374- // need this special case here.
375- ms . prepend ( injectionCode ) ;
376- }
377-
378- return {
379- code : ms . toString ( ) ,
380- map : ms . generateMap ( { file : chunk . fileName , hires : "boundary" } ) ,
381- } ;
382- } ,
383- } ;
384- }
385-
386344export function createRollupDebugIdUploadHooks (
387345 upload : ( buildArtifacts : string [ ] ) => Promise < void > ,
388346 _logger : Logger ,
0 commit comments