From 66b4d4efe735c3362e7af02f7fd846c1ea44e1a1 Mon Sep 17 00:00:00 2001 From: Ylya Date: Tue, 4 Aug 2026 19:16:46 +0200 Subject: [PATCH] fix(pack): handle paths containing spaces in build and dev-server --- packages/pack/bin/protonPack.js | 27 +++++++++++++++++++-------- packages/pack/scripts/validate.sh | 8 +++++--- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/packages/pack/bin/protonPack.js b/packages/pack/bin/protonPack.js index 8aa6b425a44..1bf0de38b61 100755 --- a/packages/pack/bin/protonPack.js +++ b/packages/pack/bin/protonPack.js @@ -52,8 +52,7 @@ const addGlobalOptions = (program) => { }; const getWebpackArgs = (options, env) => { - const extraWebpackArgs = env.args.join(' '); - return `--env protonPackOptions=${JSON.stringify(options)} ${extraWebpackArgs}`; + return [`--env`, `protonPackOptions=${JSON.stringify(options)}`, ...env.args]; }; const commandWithLog = (...args) => { @@ -62,6 +61,16 @@ const commandWithLog = (...args) => { return execa.command(...args); }; +/** + * `execa.command` splits its input on whitespace, so an argument holding an absolute + * path breaks when the repository lives under a directory containing a space. + */ +const nodeScriptWithLog = (script, args, options) => { + // eslint-disable-next-line no-console + console.log(styleText('cyan', [script, ...args].join(' ')), '\n'); + return execa(process.execPath, [script, ...args], options); +}; + addGlobalOptions(program.command('build').description('create an optimized production build')) .option('--no-sri', 'disable sri') .action(async (options, env) => { @@ -71,14 +80,15 @@ addGlobalOptions(program.command('build').description('create an optimized produ const webpackArgs = getWebpackArgs(options, env); const outputPath = path.resolve('./dist'); - await commandWithLog(`rm -rf ${outputPath}`); - await commandWithLog( - `${require.resolve('webpack-cli/bin/cli.js')} --progress --output-path=${outputPath} ${webpackArgs}`, + await execa('rm', ['-rf', outputPath]); + await nodeScriptWithLog( + require.resolve('webpack-cli/bin/cli.js'), + ['--progress', `--output-path=${outputPath}`, ...webpackArgs], { stdio: 'inherit', } ); - await commandWithLog(`${path.resolve(__dirname, `../scripts/validate.sh`)} ${outputPath}`, { + await execa(path.resolve(__dirname, `../scripts/validate.sh`), [outputPath], { stdio: 'inherit', }); const dotFiles = await Promise.all( @@ -111,8 +121,9 @@ addGlobalOptions(program.command('dev-server').description('run locally')) const port = await getPort(options.port || 8080); - await commandWithLog( - `${require.resolve('webpack-cli/bin/cli.js')} serve --progress --port=${port} ${webpackArgs}`, + await nodeScriptWithLog( + require.resolve('webpack-cli/bin/cli.js'), + ['serve', '--progress', `--port=${port}`, ...webpackArgs], { stdio: 'inherit', } diff --git a/packages/pack/scripts/validate.sh b/packages/pack/scripts/validate.sh index 1a2ea64e814..932d31b60a3 100755 --- a/packages/pack/scripts/validate.sh +++ b/packages/pack/scripts/validate.sh @@ -26,12 +26,14 @@ function detect { function detectEmpty { local total=0; - for file in $(echo "$OUTPUT_FILES" | grep -E "\.$1$"); do + # Not `for file in $(...)`: that word-splits paths containing spaces. + while IFS= read -r file; do + [ -n "$file" ] || continue; if [ ! -s "$file" ]; then - ((total++)) + total=$((total + 1)); echo "[error] empty file: $file" >&2; fi; - done; + done < <(echo "$OUTPUT_FILES" | grep -E "\.$1$"); echo "$total"; }