@@ -12,6 +12,7 @@ import { constants as fsConstants } from 'node:fs';
12
12
import fs from 'node:fs/promises' ;
13
13
import path from 'node:path' ;
14
14
import { BuildOutputFile } from '../../tools/esbuild/bundler-context' ;
15
+ import { BuildOutputAsset } from '../../tools/esbuild/bundler-execution-result' ;
15
16
import { buildApplicationInternal } from '../application' ;
16
17
import { Schema as ApplicationBuilderOptions } from '../application/schema' ;
17
18
import { logBuilderStatusWarnings } from './builder-status-warnings' ;
@@ -74,36 +75,55 @@ function normalizeOptions(options: BrowserBuilderOptions): ApplicationBuilderOpt
74
75
// and not output browser files into '/browser'.
75
76
async function writeResultFiles (
76
77
outputFiles : BuildOutputFile [ ] ,
77
- assetFiles : { source : string ; destination : string } [ ] | undefined ,
78
+ assetFiles : BuildOutputAsset [ ] | undefined ,
78
79
outputPath : string ,
79
80
) {
80
81
const directoryExists = new Set < string > ( ) ;
81
- await Promise . all (
82
- outputFiles . map ( async ( file ) => {
83
- // Ensure output subdirectories exist
84
- const basePath = path . dirname ( file . path ) ;
85
- if ( basePath && ! directoryExists . has ( basePath ) ) {
86
- await fs . mkdir ( path . join ( outputPath , basePath ) , { recursive : true } ) ;
87
- directoryExists . add ( basePath ) ;
88
- }
89
- // Write file contents
90
- await fs . writeFile ( path . join ( outputPath , file . path ) , file . contents ) ;
91
- } ) ,
92
- ) ;
82
+ const ensureDirectoryExists = async ( basePath : string ) => {
83
+ if ( basePath && ! directoryExists . has ( basePath ) ) {
84
+ await fs . mkdir ( path . join ( outputPath , basePath ) , { recursive : true } ) ;
85
+ directoryExists . add ( basePath ) ;
86
+ }
87
+ } ;
88
+
89
+ // Writes the output file to disk and ensures the containing directories are present
90
+ await emitFilesToDisk ( outputFiles , async ( file : BuildOutputFile ) => {
91
+ // Ensure output subdirectories exist
92
+ const basePath = path . dirname ( file . path ) ;
93
+ await ensureDirectoryExists ( basePath ) ;
94
+
95
+ // Write file contents
96
+ await fs . writeFile ( path . join ( outputPath , file . path ) , file . contents ) ;
97
+ } ) ;
93
98
94
99
if ( assetFiles ?. length ) {
95
- await Promise . all (
96
- assetFiles . map ( async ( { source, destination } ) => {
97
- // Ensure output subdirectories exist
98
- const basePath = path . dirname ( destination ) ;
99
- if ( basePath && ! directoryExists . has ( basePath ) ) {
100
- await fs . mkdir ( path . join ( outputPath , basePath ) , { recursive : true } ) ;
101
- directoryExists . add ( basePath ) ;
102
- }
103
- // Copy file contents
104
- await fs . copyFile ( source , path . join ( outputPath ) , fsConstants . COPYFILE_FICLONE ) ;
105
- } ) ,
106
- ) ;
100
+ await emitFilesToDisk ( assetFiles , async ( { source, destination } ) => {
101
+ const basePath = path . dirname ( destination ) ;
102
+
103
+ // Ensure output subdirectories exist
104
+ await ensureDirectoryExists ( basePath ) ;
105
+
106
+ // Copy file contents
107
+ await fs . copyFile ( source , path . join ( outputPath , destination ) , fsConstants . COPYFILE_FICLONE ) ;
108
+ } ) ;
109
+ }
110
+ }
111
+
112
+ const MAX_CONCURRENT_WRITES = 64 ;
113
+ async function emitFilesToDisk < T = BuildOutputAsset | BuildOutputFile > (
114
+ files : T [ ] ,
115
+ writeFileCallback : ( file : T ) => Promise < void > ,
116
+ ) : Promise < void > {
117
+ // Write files in groups of MAX_CONCURRENT_WRITES to avoid too many open files
118
+ for ( let fileIndex = 0 ; fileIndex < files . length ; ) {
119
+ const groupMax = Math . min ( fileIndex + MAX_CONCURRENT_WRITES , files . length ) ;
120
+
121
+ const actions = [ ] ;
122
+ while ( fileIndex < groupMax ) {
123
+ actions . push ( writeFileCallback ( files [ fileIndex ++ ] ) ) ;
124
+ }
125
+
126
+ await Promise . all ( actions ) ;
107
127
}
108
128
}
109
129
0 commit comments