@@ -20,11 +20,8 @@ import {
20
20
lookupFile ,
21
21
normalizeId ,
22
22
normalizePath ,
23
- removeDir ,
24
23
removeLeadingSlash ,
25
- renameDir ,
26
24
tryStatSync ,
27
- writeFile ,
28
25
} from '../utils'
29
26
import { transformWithEsbuild } from '../plugins/esbuild'
30
27
import { ESBUILD_MODULES_TARGET } from '../constants'
@@ -164,6 +161,9 @@ export interface DepOptimizationResult {
164
161
* to be able to discard the result
165
162
*/
166
163
commit : ( ) => Promise < void >
164
+ /**
165
+ * @deprecated noop
166
+ */
167
167
cancel : ( ) => void
168
168
}
169
169
@@ -474,23 +474,6 @@ export function runOptimizeDeps(
474
474
}
475
475
476
476
const depsCacheDir = getDepsCacheDir ( resolvedConfig , ssr )
477
- const processingCacheDir = getProcessingDepsCacheDir ( resolvedConfig , ssr )
478
-
479
- // Create a temporal directory so we don't need to delete optimized deps
480
- // until they have been processed. This also avoids leaving the deps cache
481
- // directory in a corrupted state if there is an error
482
- if ( fs . existsSync ( processingCacheDir ) ) {
483
- emptyDir ( processingCacheDir )
484
- } else {
485
- fs . mkdirSync ( processingCacheDir , { recursive : true } )
486
- }
487
-
488
- // a hint for Node.js
489
- // all files in the cache directory should be recognized as ES modules
490
- writeFile (
491
- path . resolve ( processingCacheDir , 'package.json' ) ,
492
- JSON . stringify ( { type : 'module' } ) ,
493
- )
494
477
495
478
const metadata = initDepsOptimizerMetadata ( config , ssr )
496
479
@@ -505,38 +488,16 @@ export function runOptimizeDeps(
505
488
506
489
const qualifiedIds = Object . keys ( depsInfo )
507
490
508
- let cleaned = false
509
- const cleanUp = ( ) => {
510
- if ( ! cleaned ) {
511
- cleaned = true
512
- // No need to wait, we can clean up in the background because temp folders
513
- // are unique per run
514
- fsp . rm ( processingCacheDir , { recursive : true , force : true } ) . catch ( ( ) => {
515
- // Ignore errors
516
- } )
517
- }
518
- }
519
- const createProcessingResult = ( ) => ( {
491
+ const createEmptyProcessingResult = ( ) => ( {
520
492
metadata,
521
- async commit ( ) {
522
- if ( cleaned ) {
523
- throw new Error (
524
- `Vite Internal Error: Can't commit optimizeDeps processing result, it has already been cancelled.` ,
525
- )
526
- }
527
- // Write metadata file, delete `deps` folder and rename the `processing` folder to `deps`
528
- // Processing is done, we can now replace the depsCacheDir with processingCacheDir
529
- // Rewire the file paths from the temporal processing dir to the final deps cache dir
530
- await removeDir ( depsCacheDir )
531
- await renameDir ( processingCacheDir , depsCacheDir )
532
- } ,
533
- cancel : cleanUp ,
493
+ commit : async ( ) => { } ,
494
+ cancel : async ( ) => { } ,
534
495
} )
535
496
536
497
if ( ! qualifiedIds . length ) {
537
498
return {
538
- cancel : async ( ) => cleanUp ( ) ,
539
- result : Promise . resolve ( createProcessingResult ( ) ) ,
499
+ result : Promise . resolve ( createEmptyProcessingResult ( ) ) ,
500
+ cancel : async ( ) => { } ,
540
501
}
541
502
}
542
503
@@ -546,19 +507,19 @@ export function runOptimizeDeps(
546
507
resolvedConfig ,
547
508
depsInfo ,
548
509
ssr ,
549
- processingCacheDir ,
510
+ depsCacheDir ,
550
511
optimizerContext ,
551
512
)
552
513
553
- const result = preparedRun . then ( ( { context, idToExports } ) => {
514
+ const runResult = preparedRun . then ( ( { context, idToExports } ) => {
554
515
function disposeContext ( ) {
555
516
return context ?. dispose ( ) . catch ( ( e ) => {
556
517
config . logger . error ( 'Failed to dispose esbuild context' , { error : e } )
557
518
} )
558
519
}
559
520
if ( ! context || optimizerContext . cancelled ) {
560
521
disposeContext ( )
561
- return createProcessingResult ( )
522
+ return createEmptyProcessingResult ( )
562
523
}
563
524
564
525
return context
@@ -569,15 +530,11 @@ export function runOptimizeDeps(
569
530
// the paths in `meta.outputs` are relative to `process.cwd()`
570
531
const processingCacheDirOutputPath = path . relative (
571
532
process . cwd ( ) ,
572
- processingCacheDir ,
533
+ depsCacheDir ,
573
534
)
574
535
575
536
for ( const id in depsInfo ) {
576
- const output = esbuildOutputFromId (
577
- meta . outputs ,
578
- id ,
579
- processingCacheDir ,
580
- )
537
+ const output = esbuildOutputFromId ( meta . outputs , id , depsCacheDir )
581
538
582
539
const { exportsData, ...info } = depsInfo [ id ]
583
540
addOptimizedDepInfo ( metadata , 'optimized' , {
@@ -624,23 +581,64 @@ export function runOptimizeDeps(
624
581
}
625
582
}
626
583
627
- const dataPath = path . join ( processingCacheDir , '_metadata.json' )
628
- writeFile (
629
- dataPath ,
630
- stringifyDepsOptimizerMetadata ( metadata , depsCacheDir ) ,
631
- )
632
-
633
584
debug (
634
585
`Dependencies bundled in ${ ( performance . now ( ) - start ) . toFixed ( 2 ) } ms` ,
635
586
)
636
587
637
- return createProcessingResult ( )
588
+ return {
589
+ metadata,
590
+ async commit ( ) {
591
+ // Write this run of pre-bundled dependencies to the deps cache
592
+
593
+ // Get a list of old files in the deps directory to delete the stale ones
594
+ const oldFilesPaths : string [ ] = [ ]
595
+ if ( ! fs . existsSync ( depsCacheDir ) ) {
596
+ fs . mkdirSync ( depsCacheDir , { recursive : true } )
597
+ } else {
598
+ oldFilesPaths . push (
599
+ ...( await fsp . readdir ( depsCacheDir ) ) . map ( ( f ) =>
600
+ path . join ( depsCacheDir , f ) ,
601
+ ) ,
602
+ )
603
+ }
604
+
605
+ const newFilesPaths = new Set < string > ( )
606
+ const files : Promise < void > [ ] = [ ]
607
+ const write = ( filePath : string , content : string ) => {
608
+ newFilesPaths . add ( filePath )
609
+ files . push ( fsp . writeFile ( filePath , content ) )
610
+ }
611
+
612
+ // a hint for Node.js
613
+ // all files in the cache directory should be recognized as ES modules
614
+ write (
615
+ path . resolve ( depsCacheDir , 'package.json' ) ,
616
+ '{\n "type": "module"\n}\n' ,
617
+ )
618
+
619
+ write (
620
+ path . join ( depsCacheDir , '_metadata.json' ) ,
621
+ stringifyDepsOptimizerMetadata ( metadata , depsCacheDir ) ,
622
+ )
623
+
624
+ for ( const outputFile of result . outputFiles ! )
625
+ write ( outputFile . path , outputFile . text )
626
+
627
+ // Clean up old files in the background
628
+ for ( const filePath of oldFilesPaths )
629
+ if ( ! newFilesPaths . has ( filePath ) ) fsp . unlink ( filePath )
630
+
631
+ await Promise . all ( files )
632
+ } ,
633
+ cancel : ( ) => { } ,
634
+ }
638
635
} )
636
+
639
637
. catch ( ( e ) => {
640
638
if ( e . errors && e . message . includes ( 'The build was canceled' ) ) {
641
639
// esbuild logs an error when cancelling, but this is expected so
642
640
// return an empty result instead
643
- return createProcessingResult ( )
641
+ return createEmptyProcessingResult ( )
644
642
}
645
643
throw e
646
644
} )
@@ -649,18 +647,13 @@ export function runOptimizeDeps(
649
647
} )
650
648
} )
651
649
652
- result . catch ( ( ) => {
653
- cleanUp ( )
654
- } )
655
-
656
650
return {
657
651
async cancel ( ) {
658
652
optimizerContext . cancelled = true
659
653
const { context } = await preparedRun
660
654
await context ?. cancel ( )
661
- cleanUp ( )
662
655
} ,
663
- result,
656
+ result : runResult ,
664
657
}
665
658
}
666
659
@@ -760,6 +753,9 @@ async function prepareEsbuildOptimizerRun(
760
753
absWorkingDir : process . cwd ( ) ,
761
754
entryPoints : Object . keys ( flatIdDeps ) ,
762
755
bundle : true ,
756
+ // Don't write to disk, we'll only write the files if the build isn't invalidated
757
+ // by newly discovered dependencies
758
+ write : false ,
763
759
// We can't use platform 'neutral', as esbuild has custom handling
764
760
// when the platform is 'node' or 'browser' that can't be emulated
765
761
// by using mainFields and conditions
@@ -934,15 +930,6 @@ export function getDepsCacheDir(config: ResolvedConfig, ssr: boolean): string {
934
930
return getDepsCacheDirPrefix ( config ) + getDepsCacheSuffix ( config , ssr )
935
931
}
936
932
937
- function getProcessingDepsCacheDir ( config : ResolvedConfig , ssr : boolean ) {
938
- return (
939
- getDepsCacheDirPrefix ( config ) +
940
- getDepsCacheSuffix ( config , ssr ) +
941
- '_temp_' +
942
- getHash ( Date . now ( ) . toString ( ) )
943
- )
944
- }
945
-
946
933
export function getDepsCacheDirPrefix ( config : ResolvedConfig ) : string {
947
934
return normalizePath ( path . resolve ( config . cacheDir , 'deps' ) )
948
935
}
@@ -1305,29 +1292,3 @@ export async function optimizedDepNeedsInterop(
1305
1292
}
1306
1293
return depInfo ?. needsInterop
1307
1294
}
1308
-
1309
- const MAX_TEMP_DIR_AGE_MS = 24 * 60 * 60 * 1000
1310
- export async function cleanupDepsCacheStaleDirs (
1311
- config : ResolvedConfig ,
1312
- ) : Promise < void > {
1313
- try {
1314
- const cacheDir = path . resolve ( config . cacheDir )
1315
- if ( fs . existsSync ( cacheDir ) ) {
1316
- const dirents = await fsp . readdir ( cacheDir , { withFileTypes : true } )
1317
- for ( const dirent of dirents ) {
1318
- if ( dirent . isDirectory ( ) && dirent . name . includes ( '_temp_' ) ) {
1319
- const tempDirPath = path . resolve ( config . cacheDir , dirent . name )
1320
- const stats = await fsp . stat ( tempDirPath ) . catch ( ( _ ) => null )
1321
- if (
1322
- stats ?. mtime &&
1323
- Date . now ( ) - stats . mtime . getTime ( ) > MAX_TEMP_DIR_AGE_MS
1324
- ) {
1325
- await removeDir ( tempDirPath )
1326
- }
1327
- }
1328
- }
1329
- }
1330
- } catch ( err ) {
1331
- config . logger . error ( err )
1332
- }
1333
- }
0 commit comments