Skip to content

Commit b49c429

Browse files
Add resilliency to errors on concurrent build asset writes
1 parent 268feef commit b49c429

File tree

1 file changed

+38
-16
lines changed
  • packages/app/src/cli/services/extensions

1 file changed

+38
-16
lines changed

packages/app/src/cli/services/extensions/bundle.ts

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,7 @@ export async function bundleThemeExtension(
6868
options.stdout.write(`Bundling theme extension ${extension.localIdentifier}...`)
6969
const files = await themeExtensionFiles(extension)
7070

71-
await Promise.all(
72-
files.map(function (filepath) {
73-
const relativePathName = relativePath(extension.directory, filepath)
74-
const outputFile = joinPath(extension.outputPath, relativePathName)
75-
if (filepath === outputFile) return
76-
return copyFile(filepath, outputFile)
77-
}),
78-
)
71+
await copyFiles(files, extension.directory, extension.outputPath)
7972
}
8073

8174
export async function copyFilesForExtension(
@@ -93,14 +86,8 @@ export async function copyFilesForExtension(
9386
ignore: ignored,
9487
})
9588

96-
await Promise.all(
97-
files.map(function (filepath) {
98-
const relativePathName = relativePath(extension.directory, filepath)
99-
const outputFile = joinPath(extension.outputPath, relativePathName)
100-
if (filepath === outputFile) return
101-
return copyFile(filepath, outputFile)
102-
}),
103-
)
89+
await copyFiles(files, extension.directory, extension.outputPath)
90+
10491
options.stdout.write(`${extension.localIdentifier} successfully built`)
10592
}
10693

@@ -121,6 +108,41 @@ function onResult(result: Awaited<ReturnType<typeof esBuild>> | null, options: B
121108
}
122109
}
123110

111+
async function copyFiles(files: string[], directory: string, outputPath: string): Promise<void> {
112+
const results = await Promise.allSettled(
113+
files.map(async function (filepath) {
114+
const relativePathName = relativePath(directory, filepath)
115+
const outputFile = joinPath(outputPath, relativePathName)
116+
if (filepath === outputFile) return {status: 'skipped', filepath}
117+
118+
try {
119+
await copyFile(filepath, outputFile)
120+
return {status: 'success', filepath}
121+
// eslint-disable-next-line no-catch-all/no-catch-all
122+
} catch (error) {
123+
// Log warning but don't fail the entire process
124+
// We intentionally catch all errors here to continue copying other files
125+
outputDebug(`Failed to copy file ${filepath}: ${error}`)
126+
return {status: 'failed', filepath, error}
127+
}
128+
}),
129+
)
130+
131+
// Report any failures as warnings
132+
const failures = results.filter((result) => {
133+
return result.status === 'rejected' || (result.status === 'fulfilled' && result.value?.status === 'failed')
134+
})
135+
136+
if (failures.length > 0) {
137+
const failedFiles = failures.map((failure) => {
138+
if (failure.status === 'rejected') return 'unknown file'
139+
const value = (failure as PromiseFulfilledResult<{status: string; filepath: string}>).value
140+
return value.filepath
141+
})
142+
outputDebug(`Warning: ${failures.length} file(s) could not be copied: ${failedFiles.join(', ')}`)
143+
}
144+
}
145+
124146
export function getESBuildOptions(options: BundleOptions, processEnv = process.env): Parameters<typeof esContext>[0] {
125147
const validEnvs = pickBy(processEnv, (value, key) => EsbuildEnvVarRegex.test(key) && value)
126148

0 commit comments

Comments
 (0)