@@ -12,6 +12,7 @@ import { constants as fsConstants } from 'node:fs';
1212import fs from 'node:fs/promises' ;
1313import path from 'node:path' ;
1414import { BuildOutputFile } from '../../tools/esbuild/bundler-context' ;
15+ import { BuildOutputAsset } from '../../tools/esbuild/bundler-execution-result' ;
1516import { buildApplicationInternal } from '../application' ;
1617import { Schema as ApplicationBuilderOptions } from '../application/schema' ;
1718import { logBuilderStatusWarnings } from './builder-status-warnings' ;
@@ -74,36 +75,57 @@ function normalizeOptions(options: BrowserBuilderOptions): ApplicationBuilderOpt
7475// and not output browser files into '/browser'.
7576async function writeResultFiles (
7677 outputFiles : BuildOutputFile [ ] ,
77- assetFiles : { source : string ; destination : string } [ ] | undefined ,
78+ assetFiles : BuildOutputAsset [ ] | undefined ,
7879 outputPath : string ,
7980) {
8081 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+ const fullOutputPath = file . fullOutputPath ;
92+ // Ensure output subdirectories exist
93+ const basePath = path . dirname ( fullOutputPath ) ;
94+ await ensureDirectoryExists ( basePath ) ;
95+
96+ // Write file contents
97+ await fs . writeFile ( path . join ( outputPath , fullOutputPath ) , file . contents ) ;
98+ } ) ;
9399
94100 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- ) ;
101+ await emitFilesToDisk ( assetFiles , async ( asset : BuildOutputAsset ) => {
102+ const destination = path . join ( outputPath , asset . destination ) ;
103+ const basePath = path . dirname ( destination ) ;
104+
105+ // Ensure output subdirectories exist
106+ await ensureDirectoryExists ( basePath ) ;
107+
108+ // Copy file contents
109+ await fs . copyFile ( asset . source , destination , fsConstants . COPYFILE_FICLONE ) ;
110+ } ) ;
111+ }
112+ }
113+
114+ const MAX_CONCURRENT_WRITES = 64 ;
115+ async function emitFilesToDisk < T = BuildOutputAsset | BuildOutputFile > (
116+ files : T [ ] ,
117+ writeFileCallback : ( asset : T ) => Promise < void > ,
118+ ) : Promise < void > {
119+ // Write files in groups of MAX_CONCURRENT_WRITES to avoid too many open files
120+ for ( let fileIndex = 0 ; fileIndex < files . length ; ) {
121+ const groupMax = Math . min ( fileIndex + MAX_CONCURRENT_WRITES , files . length ) ;
122+
123+ const actions = [ ] ;
124+ while ( fileIndex < groupMax ) {
125+ actions . push ( writeFileCallback ( files [ fileIndex ++ ] ) ) ;
126+ }
127+
128+ await Promise . all ( actions ) ;
107129 }
108130}
109131
0 commit comments