Node.js使用exec执行Marp markdown构建命令无响应问题排查
问题核心原因
- 直接拼接命令字符串的方式存在隐患:如果匹配到的
.marp.md文件路径/文件名包含空格、shell特殊字符(比如&、*、括号等),exec调用shell解析命令时会把参数拆分错误,导致Marp命令实际收到的参数不符合预期,无法正常执行甚至卡住。 - 缺少异步流程控制:你用forEach循环批量启动exec子进程,所有子进程都是异步执行的,Node.js默认会等待所有活跃子进程退出才会终止主进程,如果有子进程因为参数错误卡住无输出,主进程就会一直挂住。另外exec默认只有100KB的stdout/stderr缓冲区,如果Marp输出内容超过这个大小,子进程也会直接挂死。
修复方案
优先用execFile替代exec,直接传参数数组可以避开shell解析参数的问题,同时用Promise做异步流程控制,等待所有任务完成后主动退出进程,修复后的代码如下:
const glob = require("glob"); const cp = require("child_process"); // 包装execFile为Promise版本,方便异步控制 function execFilePromise(cmd, args, options = {}) { return new Promise((resolve, reject) => { const proc = cp.execFile(cmd, args, { maxBuffer: 10 * 1024 * 1024, // 缓冲区调整为10MB,足够覆盖Marp的输出 ...options }, (err, stdout, stderr) => { if (err) { err.stdout = stdout; err.stderr = stderr; return reject(err); } resolve({ stdout, stderr }); }); proc.on('exit', (code) => { console.log(`文件处理完成:${args[0]},退出码:${code}`); }); }); } glob("lab*/*.marp.md", {}, async function (err, files) { if (err) { console.error('文件匹配失败:', err); process.exit(1); } try { // 批量生成转换任务 const tasks = files.map(file => { const destination = file.replace(".md", ""); // 直接传参数数组,无需拼接命令字符串,避免空格/特殊字符解析问题 return execFilePromise('marp', [ file, '--allow-local-files', '--pdf', '-o', `${destination}.pdf` ]); }); await Promise.all(tasks); console.log('所有文件转换完成'); process.exit(0); } catch (e) { console.error('转换出错:', e); console.error('错误输出stdout:', e.stdout); console.error('错误输出stderr:', e.stderr); process.exit(1); } });
额外排查建议
如果修改后仍执行失败,可以在终端执行which marp(Linux/Mac)或者where marp(Windows)拿到Marp的绝对路径,替换掉代码中execFilePromise的第一个参数,避免Node.js进程的PATH环境变量和终端的PATH不一致、找不到Marp命令的问题。
内容的提问来源于stack exchange,提问作者Node.JS
相关产品推荐
相关产品推荐

