NodeJS迁移函数中child_process spawn调用ENOENT错误排查求助
我尝试复刻一个代码库中的migrate函数,改用Node.js(而非TypeScript)开发,大部分配置已完成,但运行迁移函数时,child_process.spawn调用自定义的node-pg-migrate文件出现ENOENT错误,提示找不到该文件。
相关代码
migrate.js
import { spawn } from 'child_process'; import * as path from 'path'; import dotenv from 'dotenv'; import * as url from 'node:url'; dotenv.config(); const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); export function migrate(commandArguments, migrationsDir = __dirname) { const spawnArgs = ['--migrations-dir', migrationsDir, ...commandArguments]; console.log('Running command:'); console.dir(`node-pg-migrate ${spawnArgs.join(' ')}`); console.log(`Spawn Path: \n${path.resolve(migrationsDir, 'node-pg-migrate')}\n`); const child = spawn( path.resolve(migrationsDir, 'node-pg-migrate'), spawnArgs, { env: { ...process.env }, windowsVerbatimArguments: false } ); child.on('error', function (error) { console.log(error.message); }); child.stdout.on('data', function (data) { console.log('stdout output: '); console.log(data.toString()); }); child.stderr.on('data', function (data) { console.log('stderr output: '); console.log(data.toString()); }); child.on('close', (code, signal) => { console.log(`child process exited with code: ${code} and signal: ${signal}`); }); return child; } //ES6 Main Check if (import.meta.url.startsWith('file:')) { const modulePath = url.fileURLToPath(import.meta.url); if (process.argv[1] === modulePath) { migrate(process.argv.slice(2), path.resolve(__dirname, '../migrations')); } }
自定义node-pg-migrate文件
#!usr/bin/env node require('../config/nodeconfig.json') require('../node_modules/node-pg-migrate/bin/node-pg-migrate')
执行输出
在PowerShell中执行npm run migrate up,输出如下:
npm WARN config global
--global,--localare deprecated. Use--location=globalinstead.desktop-server@1.0.0 migrate
node ./migrations/migrate.js "up"Running command: 'node-pg-migrate --migrations-dir C:\Users\M\NodeJSProjects\xxxx\Prototype2\desktop-server\migrations up'
Spawn Path:
C:\Users\M\NodeJSProjects\xxxx\Prototype2\desktop-server\migrations\node-pg-migrate
spawn C:\Users\M\NodeJSProjects\xxxx\Prototype2\desktop-server\migrations\node-pg-migrate ENOENT child process exited with code: -4058 and signal: null
已尝试设置windowsVerbatimArguments为true、注释node-pg-migrate内所有代码、添加文件路径到$PATH变量,但问题依旧,请问原因是什么?
核心原因
- Windows文件扩展名识别问题:自定义的
node-pg-migrate文件没有.js扩展名,Windows系统无法识别这是可执行的Node.js脚本,spawn无法正确解析并打开文件。 - Shebang行语法错误:自定义文件的Shebang行
#!usr/bin/env node缺少根路径斜杠,正确写法应为#!/usr/bin/env node——该问题在类Unix系统影响更大,但Windows下也需保证语法规范。 - Spawn调用逻辑错误:Windows下直接spawn脚本文件时,必须明确指定用Node.js程序来执行它,而非直接调用脚本路径。
解决步骤
步骤1:给自定义脚本添加扩展名
将node-pg-migrate重命名为node-pg-migrate.js,让Windows系统识别这是Node.js脚本文件。
步骤2:修正Shebang行(可选但规范)
修改node-pg-migrate.js的第一行为:
#!/usr/bin/env node
步骤3:调整Spawn调用逻辑
在migrate.js中,将spawn的执行主体改为node,把脚本路径作为第一个参数传入:
const child = spawn( 'node', // 明确使用Node.js执行脚本 [path.resolve(migrationsDir, 'node-pg-migrate.js'), ...spawnArgs], // 脚本路径作为第一个参数,后续跟上原参数 { env: { ...process.env }, windowsVerbatimArguments: false } );
步骤4:验证路径正确性
可以在代码中增加日志,确认path.resolve(migrationsDir, 'node-pg-migrate.js')指向的路径确实存在对应的文件。
额外说明
Windows系统中,spawn直接调用无扩展名文件时,只会匹配系统注册的可执行文件扩展名(如.exe、.bat),.js文件需要通过node命令明确执行。修改后的调用方式可同时兼容Windows和类Unix系统。
内容的提问来源于stack exchange,提问作者mpr4583

