gpt4 book ai didi

node.js - 如何将命令行参数传递给从可执行脚本启动的 NodeJS

转载 作者:太空宇宙 更新时间:2023-11-03 21:52:32 28 4
gpt4 key购买 nike

如何为从启动器脚本运行的 NodeJS 进程设置 node 的命令行参数? (sh/CMD 脚本 npm 放入 node_modules/.bin 中。)

许多 NodeJS 库/框架都带有自己的运行脚本,例如zeit/micromoleculer通常从 npm 脚本执行。这在开发中提出了一个问题,因为就我而言,我想做相当于:

node --inspect -r ts-node/register -r dotenv-safe/config src/index.ts

(当然,这没有任何作用,因为 index.ts 只是导出一些东西供运行者拾取。)

是否有一些“干净”的、最好是通用的(即不特定于暴露这些命令行参数的给定框架的运行程序)的方式,我缺少这样做,最好是作为 npm 脚本工作的方式?唯一看起来可行的事情就是例如:

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

最佳答案

一种选择是编写一个小包装脚本,使用当前进程 execPath 来运行 child_process.execFile。

所以这里的示例是能够做到的

node --expose-http2 --zero-fill-buffers -r ./some-module.js ./test.js

但实际上并没有写出来,而是让wrap.js注入(inject)参数:

Node ./wrap.js ./test.js

我测试了通过 npm 在 package.json 中运行它,它工作正常。我通过让 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,其中还包括您的参数。

我重写了代码来反射(reflect)这一点。这是一个新设置:

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();
})
})

请永远不要将这样的代码放入已发布的 Node 模块中。修改全局库函数是非常糟糕的。

关于node.js - 如何将命令行参数传递给从可执行脚本启动的 NodeJS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49785735/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com