node子进程如何输出和关闭
# 概要
本文回答 4 个问题
- webpack5 如何传入命令行参数
- node 子进程如何输出
- 如何终止 node 子进程启动的服务
- 如何查看和终止开启的服务
# webpack5 如何传入命令行参数
在升级 webpack5 的过程中,发现原来可以自定义的传参方式不受支持了,报错如下。
[webpack-cli] Error: Unknown option '--env.pageName'
[webpack-cli] Run 'webpack --help' to see available commands and options
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! s2b2c@1.0.0 dev: `webpack-dev-server --progress --config build/webpack.dev.conf.js --env.pageName "goodsCenter"`
npm ERR! Exit status 2
1
2
3
4
5
6
2
3
4
5
6
对比webpack4 (opens new window)和webpack5 (opens new window)的文档,发 现确实有所出入,举例来说。
webpack4 之前可以设置命令行如下
"scripts":{
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --env.pageName",
}
1
2
3
2
3
假如用户输入命令为
npm run dev goodsCenter
1
那么可以在webpack.dev.config.js
获取到goodsCenter
的值,这个是多页打包的功能之一。
// webpack.dev.conf.js
module.exports = (env) => {
console.log(env.pageName) // goodsCenter
}
1
2
3
4
2
3
4
现在 webpack5 不支持这种写法了,咋办呢?
想过 2 个方案:
- 使用交互式命令来获取用户选择的参数,使用
inquirer
库 - 修改命令,不直接使用 webpack 打包,而是使用 node 启动,此时可以获取用户的传参,在执行文件中另外执行 webpack 命令。
本着改动量小的原则,选择的方案二。
# webpack5 如何传入命令行参数
通过 node 中转,是可以获取命令行参数的。
使用新命令
"start": "node build/dev.js",
1
然后新增 dev.js
// build/dev.jd
const chalk = require('chalk')
const cp = require('child_process')
async function run() {
console.log(process.argv.slice(2))
const cliParams = process.argv.slice(2)
if (cliParams.length > 2) {
console.log(chalk.yellow('仅支持传入一个页面参数,多余页面会被忽略'))
}
const page = cliParams[0] || ''
const pageParam = page ? `--env pageName=${page}` : ''
const cmd = `webpack serve --progress --config build/webpack.dev.conf.js --color ${pageParam}`
const child = cp.exec(cmd)
child.stdout.pipe(process.stdout) // 输出子进程信息
child.stderr.pipe(process.stderr)
}
run()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
注意,这里新增了--color
参数,用于输出子进程信息时带上原有的颜色。
# node 子进程如何输出
上面的代码其实已经说明了。主要是调用 node
的child_process
模块 (opens new window),将子进程的输出通过管道连接到主进程,
从而输出信息。
# 如何终止 node 子进程启动的服务
如果是上面的代码,是不需要考虑子进程服务占用问题的,因为开发者通过ctrl + c
终止主进程时,子进程也会被终止。这里新开了一个 demo 来验证。
前提:全局安装http-server
,新建一个目录。
安装依赖
npm i execa -S
写入命令
"scripts": { "http": "node http.js", },
1
2
3测试代码如下
// http.js const execa = require('execa') let cp = require('child_process') const command = `http-server` // 无法输出子进程日志 // 无法ctrl + c 关闭服务。 // @issues https://github.com/sindresorhus/execa/issues/460 // 解释下:如果直接在cmd运行http-server,然后ctrl+c,服务会直接终止。 // 但这里无法关闭,进程还在继续。 windows端可以通过 netstat -ano|findstr 8080 查看 async function run1() { try { const result = await execa.command(command) console.log('result', result) } catch (e) { console.log('错误', e) } } // 可以查看子进程日志 // 无法ctrl + c 关闭服务。 async function run2() { const result = execa.command(command) result.stdout.pipe(process.stdout) result.stderr.pipe(process.stderr) } // 可以查看子进程日志 // 无法ctrl + c 关闭服务。 async function run3() { const result = execa(command, { shell: true }) result.stdout.pipe(process.stdout) result.stderr.pipe(process.stderr) } // 可以查看子进程日志 // 可以ctrl + c 关闭服务。 function run4() { const result = cp.exec(command) result.stdout.pipe(process.stdout) result.stderr.pipe(process.stderr) } // 可以查看子进程日志 // 可以ctrl + c 关闭服务。 function run5() { const result = cp.spawn(command, { shell: true }) result.stdout.pipe(process.stdout) result.stderr.pipe(process.stderr) } run3()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
可见开源库execa
并没有做到完全同 node api 一致,因此在上述代码中直接使用 child_process 的 exec()方法。
# 如何查看和终止开启的服务
在调试过程中除了通过访问已开启服务页面来检测服务是否开启之外,还可以通过下面的方法查看。
端口占用解决:
F:\h5\node_modules\webpack-dev-server\lib\Server.js:1751
throw error;
^
Error: listen EADDRINUSE: address already in use 0.0.0.0:8088
at Server.setupListenHandle [as _listen2] (net.js:1320:16)
at listenInCluster (net.js:1368:12)
at doListen (net.js:1505:7)
at processTicksAndRejections (internal/process/task_queues.js:83:21) {
errno: -4091,
syscall: 'listen',
address: '0.0.0.0',
port: 8088
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
查找开启服务的端口
netstat -ano|findstr 8088
1
发现的确存在
TCP 0.0.0.0:8088 0.0.0.0:0 LISTENING 2968
TCP 127.0.0.1:8088 127.0.0.1:52191 ESTABLISHED 2968
TCP 127.0.0.1:52191 127.0.0.1:8088 ESTABLISHED 13156
TCP 127.0.0.1:52222 127.0.0.1:8088 TIME_WAIT 0
1
2
3
4
2
3
4
干掉它,即可。
tskill 2968
1
上次更新: 2022/09/06, 15:14:50