夜听城嚣 夜听城嚣
首页
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 前端基建与架构
  • 专题分享

    • Git入门与开发
    • 前端面试题汇总
    • HTML和CSS知识点
  • 项目实践
  • 抓包工具
  • 知识管理
  • 工程部署
  • 团队规范
bug知多少
  • 少年歌行
  • 青年随笔
  • 文海泛舟
  • 此事躬行

    • 项目各工种是如何协作的
    • TBA课程学习
收藏

dwfrost

前端界的小学生
首页
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 前端基建与架构
  • 专题分享

    • Git入门与开发
    • 前端面试题汇总
    • HTML和CSS知识点
  • 项目实践
  • 抓包工具
  • 知识管理
  • 工程部署
  • 团队规范
bug知多少
  • 少年歌行
  • 青年随笔
  • 文海泛舟
  • 此事躬行

    • 项目各工种是如何协作的
    • TBA课程学习
收藏
  • chrome控制台怎么复制对象
  • 小程序键盘弹起后顶起自定义导航问题
  • node子进程如何输出和关闭
    • 代理域名后webpack热更新失效及解决
    • 小程序scroll-view隐藏滚动条
    • npm包相关
    • electron下载慢解决
    • electron开发踩坑
    • mac升级后git找不到
    • electron打包找不到python
    • 安装imagemin-mozjpeg失败
    • 开发中的bug类型踩坑
    • 云端web项目开发踩坑
    • 如何快速定位bug
    • bug知多少
    frost
    2021-12-07

    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

    对比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

    假如用户输入命令为

    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

    现在 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

    注意,这里新增了--color参数,用于输出子进程信息时带上原有的颜色。

    # node 子进程如何输出

    上面的代码其实已经说明了。主要是调用 node 的child_process模块 (opens new window),将子进程的输出通过管道连接到主进程, 从而输出信息。

    # 如何终止 node 子进程启动的服务

    如果是上面的代码,是不需要考虑子进程服务占用问题的,因为开发者通过ctrl + c终止主进程时,子进程也会被终止。这里新开了一个 demo 来验证。

    前提:全局安装http-server,新建一个目录。

    1. 安装依赖npm i execa -S

    2. 写入命令

          "scripts": {
              "http": "node http.js",
          },
      
      1
      2
      3
    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

    查找开启服务的端口

    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

    干掉它,即可。

    tskill 2968
    
    1
    #node
    上次更新: 2022/09/06, 15:14:50
    小程序键盘弹起后顶起自定义导航问题
    代理域名后webpack热更新失效及解决

    ← 小程序键盘弹起后顶起自定义导航问题 代理域名后webpack热更新失效及解决→

    最近更新
    01
    提交代码时修改commit消息
    04-09
    02
    如何快速定位bug
    02-20
    03
    云端web项目开发踩坑
    08-25
    更多文章>
    Theme by Vdoing | Copyright © 2021-2025 dwfrost | 粤ICP备2021118995号
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式
    ×