@@ -185,32 +185,46 @@ export function sentryUnpluginFactory({
185185 } )
186186 ) ;
187187
188- async function deleteFilesUpForDeletion ( ) {
189- const filesToDeleteAfterUpload =
190- options . sourcemaps ?. filesToDeleteAfterUpload ?? options . sourcemaps ?. deleteFilesAfterUpload ;
191-
192- if ( filesToDeleteAfterUpload ) {
193- const filePathsToDelete = await glob ( filesToDeleteAfterUpload , {
194- absolute : true ,
195- nodir : true ,
196- } ) ;
188+ // We have multiple plugins depending on generated source map files. (debug ID upload, legacy upload)
189+ // Additionally, we also want to have the functionality to delete files after uploading sourcemaps.
190+ // All of these plugins and the delete functionality need to run in the same hook (`writeBundle`).
191+ // Since the plugins among themselves are not aware of when they run and finish, we need a system to
192+ // track their dependencies on the generated files, so that we can initiate the file deletion only after
193+ // nothing depends on the files anymore.
194+ const dependenciesOnSourcemapFiles = new Set < symbol > ( ) ;
195+ const sourcemapFileDependencySubscribers : ( ( ) => void ) [ ] = [ ] ;
196+
197+ function notifySourcemapFileDependencySubscribers ( ) {
198+ sourcemapFileDependencySubscribers . forEach ( ( subscriber ) => {
199+ subscriber ( ) ;
200+ } ) ;
201+ }
202+
203+ function createDependencyOnSourcemapFiles ( ) {
204+ const dependencyIdentifier = Symbol ( ) ;
205+ dependenciesOnSourcemapFiles . add ( dependencyIdentifier ) ;
197206
198- filePathsToDelete . forEach ( ( filePathToDelete ) => {
199- logger . debug ( `Deleting asset after upload: ${ filePathToDelete } ` ) ;
207+ return function freeDependencyOnSourcemapFiles ( ) {
208+ dependenciesOnSourcemapFiles . delete ( dependencyIdentifier ) ;
209+ notifySourcemapFileDependencySubscribers ( ) ;
210+ } ;
211+ }
212+
213+ /**
214+ * Returns a Promise that resolves when all the currently active dependencies are freed again.
215+ */
216+ function waitUntilSourcemapFileDependenciesAreFreed ( ) {
217+ return new Promise < void > ( ( resolve ) => {
218+ sourcemapFileDependencySubscribers . push ( ( ) => {
219+ if ( dependenciesOnSourcemapFiles . size === 0 ) {
220+ resolve ( ) ;
221+ }
200222 } ) ;
201223
202- await Promise . all (
203- filePathsToDelete . map ( ( filePathToDelete ) =>
204- fs . promises . rm ( filePathToDelete , { force : true } ) . catch ( ( e ) => {
205- // This is allowed to fail - we just don't do anything
206- logger . debug (
207- `An error occurred while attempting to delete asset: ${ filePathToDelete } ` ,
208- e
209- ) ;
210- } )
211- )
212- ) ;
213- }
224+ if ( dependenciesOnSourcemapFiles . size === 0 ) {
225+ resolve ( ) ;
226+ }
227+ } ) ;
214228 }
215229
216230 if ( options . bundleSizeOptimizations ) {
@@ -326,22 +340,13 @@ export function sentryUnpluginFactory({
326340 vcsRemote : options . release . vcsRemote ,
327341 headers : options . headers ,
328342 } ,
329- deleteFilesUpForDeletion ,
343+ freeDependencyOnSourcemapFiles : createDependencyOnSourcemapFiles ( ) ,
330344 } )
331345 ) ;
332346 }
333347
334348 plugins . push ( debugIdInjectionPlugin ( logger ) ) ;
335349
336- plugins . push (
337- fileDeletionPlugin ( {
338- deleteFilesUpForDeletion,
339- handleRecoverableError,
340- sentryHub,
341- sentryClient,
342- } )
343- ) ;
344-
345350 if ( ! options . authToken ) {
346351 logger . warn (
347352 "No auth token provided. Will not upload source maps. Please set the `authToken` option. You can find information on how to generate a Sentry auth token here: https://docs.sentry.io/api/auth/"
@@ -360,7 +365,7 @@ export function sentryUnpluginFactory({
360365 createDebugIdUploadFunction ( {
361366 assets : options . sourcemaps ?. assets ,
362367 ignore : options . sourcemaps ?. ignore ,
363- deleteFilesUpForDeletion ,
368+ freeDependencyOnSourcemapFiles : createDependencyOnSourcemapFiles ( ) ,
364369 dist : options . release . dist ,
365370 releaseName : options . release . name ,
366371 logger : logger ,
@@ -396,6 +401,21 @@ export function sentryUnpluginFactory({
396401 }
397402 }
398403
404+ plugins . push (
405+ fileDeletionPlugin ( {
406+ // It is very important that this is only called after all other dependencies have been created with `createDependencyOnSourcemapFiles`.
407+ // Ideally, we always register this plugin last.
408+ dependenciesAreFreedPromise : waitUntilSourcemapFileDependenciesAreFreed ( ) ,
409+ filesToDeleteAfterUpload :
410+ options . sourcemaps ?. filesToDeleteAfterUpload ??
411+ options . sourcemaps ?. deleteFilesAfterUpload ,
412+ logger,
413+ handleRecoverableError,
414+ sentryHub,
415+ sentryClient,
416+ } )
417+ ) ;
418+
399419 return plugins ;
400420 } ) ;
401421}
0 commit comments