一种选择是编写一个小的包装脚本,使用当前进程的 execPath 来运行 child_process.execFile。
因此,这里的示例是能够执行以下命令:
node --expose-http2 --zero-fill-buffers -r ./some-module.js ./test.js
但实际上不需要将其写出来,而是让 wrap.js 注入参数:
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);
and
some-module.js
global.testval = 2
and
test.js
console.log('hi guys, did the wrap work?', global.testval)
编辑:经过进一步思考,这个解决方案只适用于包装初始运行程序。但是大多数工具(如mocha)会重新生成子进程,从而失去此效果。要真正完成工作,您可以代理每个子进程调用,并在某种程度上强制调用spawn
等也包括您的参数。
我重写了代码以反映这一点。这里是一个新的设置:
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');
global.testvalue = 'hi there'
const customParams = ['--zero-fill-buffers'];
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)) {
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) => {
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();
})
})
请勿将这样的代码放入已发布的节点模块中。修改全局库函数非常糟糕。
child_process.exec
或child_process.spawn
调用传递的命令行参数吗? - Catalystnode -r overwrite-da-stuff.js sample.js
并且在overwrite-da-stuff.js
中指定一些自定义的 node.js 命令行参数来调用sample.js
?如果是这样的话,那么它类似于能够从应用程序代码中启用--inspect
吗?如果是这样的话,我怀疑你无法打败子进程...否则它只会允许特定的标志,这些标志不会造成安全风险。 - Catalyst-r
的作用?它会在执行指定脚本之前让 node 运行时require()
一个模块。在我的示例中,ts-node/register
是一个模块,当被 require 时,注册 ts-node 为脚本加载器,使得直接加载 TypeScript 文件成为可能,动态编译它们,而无需提前手动完成这些。类似的还有dotenv
,它会加载当前文件夹中的.env
文件,并将其内容添加到process.env
中。 - millimoose