@@ -185,32 +185,46 @@ export function sentryUnpluginFactory({
185
185
} )
186
186
) ;
187
187
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 ) ;
197
206
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
+ }
200
222
} ) ;
201
223
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
+ } ) ;
214
228
}
215
229
216
230
if ( options . bundleSizeOptimizations ) {
@@ -326,22 +340,13 @@ export function sentryUnpluginFactory({
326
340
vcsRemote : options . release . vcsRemote ,
327
341
headers : options . headers ,
328
342
} ,
329
- deleteFilesUpForDeletion ,
343
+ freeDependencyOnSourcemapFiles : createDependencyOnSourcemapFiles ( ) ,
330
344
} )
331
345
) ;
332
346
}
333
347
334
348
plugins . push ( debugIdInjectionPlugin ( logger ) ) ;
335
349
336
- plugins . push (
337
- fileDeletionPlugin ( {
338
- deleteFilesUpForDeletion,
339
- handleRecoverableError,
340
- sentryHub,
341
- sentryClient,
342
- } )
343
- ) ;
344
-
345
350
if ( ! options . authToken ) {
346
351
logger . warn (
347
352
"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({
360
365
createDebugIdUploadFunction ( {
361
366
assets : options . sourcemaps ?. assets ,
362
367
ignore : options . sourcemaps ?. ignore ,
363
- deleteFilesUpForDeletion ,
368
+ freeDependencyOnSourcemapFiles : createDependencyOnSourcemapFiles ( ) ,
364
369
dist : options . release . dist ,
365
370
releaseName : options . release . name ,
366
371
logger : logger ,
@@ -396,6 +401,21 @@ export function sentryUnpluginFactory({
396
401
}
397
402
}
398
403
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
+
399
419
return plugins ;
400
420
} ) ;
401
421
}
0 commit comments