Node watch 报引号错误
普通 Node 可用的环境选项,在 watch 子进程中报未闭合引号或丢反斜线。核对 26.11.1 重建转义逻辑及实际参数值。
同一份 NODE_OPTIONS,普通 Node 启动正常,加上 --watch 后子进程却报:
invalid value for NODE_OPTIONS (unterminated string)
Failed running 'app.cjs'. Waiting for file changes before restarting...
另一种表现更隐蔽:进程能启动,但选项值里的反斜线消失。先比较父进程的原始环境值与 watch 子进程重建的选项字符串,不要立即把问题归到外层 shell 引号。
字符串经历了第二次序列化
watch 父进程需要去掉子进程不该继承的 watch 选项。为此,它先解析 NODE_OPTIONS,得到已经拆分的选项值,再把保留项重新拼成一个环境字符串。
第一次解析会去掉用于表达值的引号和转义。如果一个值里本身含有双引号,简单包上双引号再拼接,子进程的下一次解析就可能认为字符串没有结束。带空格和反斜线的值,也可能在第二次解析时被错误地解释。
比如应用有意把进程标题设为包含 a"b 的文本,普通启动可以正确得到这个值;旧 watch 路径重建时却没有完整转义。另一个包含空格和反斜线的标题,也可能由 a \b 变成 a b。问题不只影响命令能否启动,还影响实际传到程序里的内容。
先确认不是原环境就无效
在现有受控环境中,对照普通启动和 watch 启动读取到的关键选项值。保留同一个 Node 可执行文件、启动目录和原参数,不要在比较时同时更换 shell、包装脚本或依赖。
NODE_OPTIONS 只允许特定 Node 选项,命令行也有自己的覆盖与叠加规则。若普通启动同样报非法选项或未闭合引号,应先处理原环境;只有普通路径有效、watch 子进程不同,才符合这里的重建问题。
诊断记录应只包含必要选项的脱敏值。预加载路径、调试地址或其他配置可能带有敏感内容,不需要为了检查引号把整份进程环境公开。
正式实现重新转义保留项
已核对的 Node 26.11.1 在重建字符串时,对含空格或双引号的项重新加引号,并先转义反斜线,再转义双引号。这个顺序避免把后来为双引号加入的反斜线又转义一次。无需包引号的其他项则按其解析规则保留。
这确认了该正式版本包含对应处理,并不指定最早修复补丁,也不代表所有 Node watch 问题都消失。项目应沿兼容版本选择包含此逻辑的发行包,再检查实际运行路径。
暂时不能升级时,如果某个受影响选项允许移到原启动命令行,可以逐项调整并核对语义;对于可重复选项,要保留环境与命令行之间的原有顺序。不要清空整份 NODE_OPTIONS,也不要在外层把本来已正确编码的环境值再统一转义一遍。
验收实际值与重启后的值
确认引号值不再阻止子进程启动,反斜线值也没有静默变化。再触发一次正常文件更新,检查重启后的子进程仍拿到相同内容,原有预加载和其他必需选项没有丢失。
如果问题变成应用根本不执行、不断生成新的 watch 子进程,应另查 watch 选项过滤。这与本篇保留值的序列化不同:一处决定哪些项应该留下,另一处决定留下的值能否完整传过去。


