如何为启动器脚本运行的NodeJS进程设置node
的命令行参数? (sh / CMD脚本npm
放入node_modules/.bin
。)
许多NodeJS库/框架都带有自己的跑步者脚本,例如:通常从npm
脚本执行的zeit/micro
或moleculer
。这在开发中存在问题,因为在我的情况下,我想做相同的:
node --inspect -r ts-node/register -r dotenv-safe/config src/index.ts
(当然,除了index.ts之外什么也没做什么,只是为跑步者提供了一些东西。)
是否有一些“干净的”,最好是通用的(即不是特定于给定框架的运行程序暴露那些命令行参数)我不想这样做的方式,理想情况下是一个作为npm脚本工作的方式?看起来它唯一可行的是例如micro
:
node-dev -r ts-node/register ./node_modules/micro-dev/bin/micro-dev.js ./src/index.ts
这是冗余部门冗余部门的一种口感,似乎避免了使用这些启动脚本。 (如果运行器生成其他Node进程,它也将无效,但这不是我实际遇到的问题。)我不想重复启动器脚本已经在做什么。我也知道npx
有--node-arg
,但是npx是另一种蠕虫病毒。 (在Windows上,它只有5秒的启动时间和一条虚假错误消息,只是为了运行我已经安装的脚本;如果它找不到它的.cmd
启动程序脚本,它也找不到已经安装的包,例如当使用Docker运行开发环境时。简而言之,我宁愿不使用npx。)
要清除注释中似乎出现的混乱:我想覆盖影响 NodeJS运行时本身执行转轮脚本的行为的命令行参数,而不是传递参数脚本本身或我的代码。也就是说,此处列出的选项为https://nodejs.org/api/cli.html
答案 0 :(得分:1)
我没有明确你的问题,但作为你的问题标题,我们可以使用npm库从nodejs执行任何cmd命令,如:
import Promise from 'bluebird'
import cmd from 'node-cmd'
const getAsync = Promise.promisify(cmd.get, { multiArgs: true, context: cmd })
getAsync('node -v').then(data => {
console.log('cmd data', data)
}).catch(err => {
console.log('cmd err', err)
})
答案 1 :(得分:1)
一个选项是编写一个使用当前进程execPath运行child_process.execFile的小包装器脚本。
所以这里的样本是能够做到的
node --expose-http2 --zero-fill-buffers -r ./some-module.js ./test.js
但实际上没有写出来,而是让wrap.js注入args:
node ./wrap.js ./test.js
我测试了在package.json中通过npm运行它,它运行正常。我通过让some-module.js
在全局对象上粘贴一个值,然后将其记录在test.js
中来测试它的工作情况。
涉及的文件:
wrap.js
const child_process = require('child_process');
const nodeArgs = ['--expose-http2', '--zero-fill-buffers', '-r', './some-module.js'];
const runTarget = process.argv[2];
console.log('going to wrap', runTarget, 'with', nodeArgs);
const finalArgs = nodeArgs.concat(runTarget).concat(process.argv.slice(2));
const child = child_process.execFile(
process.execPath,
finalArgs,
{
env: process.env,
cwd: process.cwd(),
stdio: 'inherit'
}, (e, stdout, stderr) => {
console.log('process completed');
if (e) {
process.emit('uncaughtException', e);
}
});
child.stdout.pipe(process.stdout);
child.stderr.pipe(process.stderr);
和
some-module.js
global.testval = 2;
和
test.js
console.log('hi guys, did the wrap work?', global.testval)
编辑:所以经过进一步思考,这个解决方案真的只能满足包装初始跑步者的需要。但是大多数工具,比如mocha重新生成一个子进程,然后会失去这种效果。要真正完成工作,您可以代理每个子进程调用,并稍微强制执行对spawn
的调用,这样也包括您的args。
我重写了代码以反映这一点。这是一个新的设置:
package.json
{
"scripts": {
"test": "node -r ./ensure-wrapped.js node_modules/mocha/$(npm view mocha bin.mocha) ./test.js"
},
"dependencies": {
"mocha": "^5.1.0"
}
}
ensure-wrapped.js
const child_process = require('child_process');
// up here we can require code or do whatever we want;
global.testvalue = 'hi there'
const customParams = ['--zero-fill-buffers'];
// the code below injects itself into any child process's spawn/fork/exec calls
// so that it propogates
const matchNodeRe = /((:?\s|^|\/)node(:?(:?\.exe)|(:?\.js)|(:?\s+)|$))/;
const ensureWrappedLocation = __filename;
const injectArgsAndAddToParamsIfPathMatchesNode = (cmd, args, params) => {
params.unshift(...customParams);
params.unshift(args);
if (!Array.isArray(args)) { // all child_proc functions do [] optionally, then other params
args = []
params.unshift(args);
}
if (!matchNodeRe.test(cmd)) {
return params;
}
args.unshift(ensureWrappedLocation);
args.unshift('-r');
return params;
}
child_process._exec = child_process.exec;
child_process.exec = (cmd, ...params) => {
// replace node.js node.exe or /path/to/node to inject -r ensure-wrapped.js ...args..
// leaves alone exec if it isn't calling node
cmd = cmd.replace(matchNodeRe, '$1 -r ' + ensureWrappedLocation + ' ');
return child_process._exec(cmd, ...params)
}
child_process._execFile = child_process.execFile;
child_process.execFile = (path, args, ...params) => {
params = injectArgsAndAddToParamsIfPathMatchesNode(path, args, params);
return child_process._execFile(path, ...params)
}
child_process._execFileSync = child_process.execFileSync;
child_process.execFileSync = (path, args, ...params) => {
params = injectArgsAndAddToParamsIfPathMatchesNode(path, args, params);
return child_process._execFileSync(path, ...params);
}
child_process._execSync = child_process.execSync;
child_process.execSync = (cmd, ...params) => {
cmd = cmd.replace(matchNodeRe, '$1 -r ' + ensureWrappedLocation + ' ');
return child_process._exec(bin, ...args)
}
child_process._fork = child_process.fork;
child_process.fork = (module, args, ...params) => {
params = injectArgsAndAddToParamsIfPathMatchesNode(process.execPath, args, params);
return child_process._fork(module, ...params);
}
child_process._spawn = child_process.spawn;
child_process.spawn = (cmd, args, ...params) => {
params = injectArgsAndAddToParamsIfPathMatchesNode(cmd, args, params);
return child_process._spawn(cmd, ...params)
}
child_process._spawnSync = child_process.spawnSync;
child_process.spawnSync = (cmd, args, ...params) => {
params = injectArgsAndAddToParamsIfPathMatchesNode(cmd, args, params);
return child_process._spawnSync(cmd, ...params);
}
test.js
describe('test', () => {
it('should have the global value pulled in by some-module.js', (done) => {
if (global.testvalue !== 'hi there') {
done(new Error('test value was not globally set'))
}
return done();
})
})
请勿将此类代码放入已发布的节点模块中。修改全局库函数非常糟糕。
答案 2 :(得分:0)
在您的nodejs应用程序被解析为名为process.argv的数组之后,命令行中传递的所有内容。所以......
node myapp.js foo bar hello 5000
在你的nodejs代码......
const args = process.argv;
console.log(args[0]);
console.log(args[1]);
console.log(args[2]);
console.log(args[3]);
会产生......
foo
bar
hello
5000