@@ -34,11 +34,11 @@ const ALLOWED_TRANSFORMATION_FILE_ENDINGS = [".js", ".ts", ".jsx", ".tsx", ".mjs
3434 * - Sourcemaps upload
3535 *
3636 * Release injection:
37- * Per default the sentry bundler plugin will inject a global `SENTRY_RELEASE` into
38- * each JavaScript/TypeScript entrypoint . On a technical level this is done by identifying
39- * entrypoints in the `resolveId` hook and prepending user code in the `transform` hook.
40- * If a user wants to inject the release into a particular set of modules instead,
41- * they can use the `releaseInjectionTargets` option.
37+ * Per default the sentry bundler plugin will inject a global `SENTRY_RELEASE` into each JavaScript/TypeScript module
38+ * that is part of the bundle . On a technical level this is done by appending an import (`import "sentry-release-injector;"`)
39+ * to all entrypoint files of the user code (see `transformInclude` and `transform` hooks). This import is then resolved
40+ * by the sentry plugin to a virtual module that sets the global variable (see `resolveId` and `load` hooks).
41+ * If a user wants to inject the release into a particular set of modules they can use the `releaseInjectionTargets` option.
4242 *
4343 * Source maps upload:
4444 *
@@ -102,8 +102,6 @@ const unplugin = createUnplugin<Options>((options, unpluginMetaContext) => {
102102 let transaction : Transaction | undefined ;
103103 let releaseInjectionSpan : Span | undefined ;
104104
105- const absolueEntrypointPaths = new Set < string > ( ) ;
106-
107105 return {
108106 name : "sentry-plugin" ,
109107 enforce : "pre" , // needed for Vite to call resolveId hook
@@ -164,11 +162,6 @@ const unplugin = createUnplugin<Options>((options, unpluginMetaContext) => {
164162 */
165163 resolveId ( id , importer , { isEntry } ) {
166164 logger . debug ( 'Called "resolveId":' , { id, importer, isEntry } ) ;
167-
168- if ( isEntry ) {
169- absolueEntrypointPaths . add ( path . resolve ( path . normalize ( id ) ) ) ;
170- }
171-
172165 return undefined ;
173166 } ,
174167
@@ -187,6 +180,10 @@ const unplugin = createUnplugin<Options>((options, unpluginMetaContext) => {
187180 // a windows style path to `releaseInjectionTargets`
188181 const normalizedId = path . normalize ( id ) ;
189182
183+ if ( id . includes ( "release-injection-file" ) ) {
184+ return true ;
185+ }
186+
190187 if ( internalOptions . releaseInjectionTargets ) {
191188 // If there's an `releaseInjectionTargets` option transform (ie. inject the release varible) when the file path matches the option.
192189 if ( typeof internalOptions . releaseInjectionTargets === "function" ) {
@@ -201,16 +198,14 @@ const unplugin = createUnplugin<Options>((options, unpluginMetaContext) => {
201198 return normalizedId === normalizedEntry ;
202199 }
203200 } ) ;
204- } else if ( absolueEntrypointPaths . has ( normalizedId ) ) {
201+ } else {
205202 const pathIsOrdinary = ! normalizedId . includes ( "?" ) && ! normalizedId . includes ( "#" ) ;
206203
207204 const pathHasAllowedFileEnding = ALLOWED_TRANSFORMATION_FILE_ENDINGS . some (
208205 ( allowedFileEnding ) => normalizedId . endsWith ( allowedFileEnding )
209206 ) ;
210207
211208 return pathIsOrdinary && pathHasAllowedFileEnding ;
212- } else {
213- return false ;
214209 }
215210 } ,
216211
@@ -228,15 +223,22 @@ const unplugin = createUnplugin<Options>((options, unpluginMetaContext) => {
228223 // The MagicString library allows us to generate sourcemaps for the changes we make to the user code.
229224 const ms = new MagicString ( code ) ;
230225
231- ms . prepend (
232- generateGlobalInjectorCode ( {
233- release : await releaseNamePromise ,
234- injectReleasesMap : internalOptions . injectReleasesMap ,
235- injectBuildInformation : internalOptions . _experiments . injectBuildInformation || false ,
236- org : internalOptions . org ,
237- project : internalOptions . project ,
238- } )
239- ) ;
226+ if ( code . includes ( "_sentry_release_injection_file" ) ) {
227+ // Appending instead of prepending has less probability of mucking with user's source maps.
228+ ms . append (
229+ generateGlobalInjectorCode ( {
230+ release : await releaseNamePromise ,
231+ injectReleasesMap : internalOptions . injectReleasesMap ,
232+ injectBuildInformation : internalOptions . _experiments . injectBuildInformation || false ,
233+ org : internalOptions . org ,
234+ project : internalOptions . project ,
235+ } )
236+ ) ;
237+ } else {
238+ // Appending instead of prepending has less probability of mucking with user's source maps.
239+ // Luckily import statements get hoisted to the top anyways.
240+ ms . append ( `;\nimport "@sentry/bundler-plugin-core/dist/release-injection-file";` ) ;
241+ }
240242
241243 if ( unpluginMetaContext . framework === "esbuild" ) {
242244 // esbuild + unplugin is buggy at the moment when we return an object with a `map` (sourcemap) property.
0 commit comments