脚手架学习-基于node多进程

这是我参与更文挑战的第9天,活动详情查看: 更文挑战

现在的代码还是基于上一篇脚手架文章的代码

一、commander脚手架初始化

使用lerna创建commander

lerna create @zl-cli-dev/command
复制代码

然后把文件夹移动到models下,修改好index文件夹后,我们需要把commder被init继承。

在commands/init中导入依赖,

package.json

"dependencies": {
   "@zl-cli-dev/command": "./../../models/command"
 }
  
npm link
复制代码

文件夹中使用如下

const Command = require('@zl-cli-dev/command')

class InitCommand extends Command {

}

function init(argv) {
    return new InitCommand(argv)

}

module.exports = init
module.exports.InitCommand = InitCommand;
复制代码

现在我们可以修改command中的代码了

class Command {
  constructor(argv) {
     console.log('Command constructor', argv)
  }

  init() {
    throw new Error('init必须实现')
  }

  exec() {
    throw new Error('exec必须实现')
  }
}

module.exports = Command;
复制代码

修改exec中index.js

if(rootFile) {
    // 在当前进程中使用
    require(rootFile).call(null, Array.from(arguments))
    // 在node子进程中调用
  }
复制代码

运行下代码,看我们的输出知否正常

zl-cli-dev init --targetPath F:\2021\web-jg\week2\zl-cli-dev\commands\init --debug test-project --force
复制代码

看到一下结果大概就是好了

image.png

与此同时,要将检查node的版本号的方法移动过来
在core/cli/lib/index.js

 function checkNodeVersion() {
   const currentVersion = process.version
   const lowestVersion = constant.LOWEST_NODE_VERSION
   if(!semver.gte(currentVersion, lowestVersion)) {
     throw new Error(colors.red(`zl-cli 需要安装 v${lowestVersion}以上版本的Node.js`))
   }
  
 }
复制代码

移动这个方法,还需要在command中加载semver和colors依赖

npm install -S semver
npm install -S colors
复制代码

改造之后代码如下

const semver = require('semver')
const colors = require('colors/safe')
const LOWEST_NODE_VERSION = '12.10.0'

class Command {
  constructor(argv) {
    // console.log('Command constructor', argv)
    this._argv = argv
    let runner = new Promise((resolve, reject) => {
      let chain = Promise.resolve()
      chain = chain.then(() => this.checkNodeVersion())
    })
  }

  checkNodeVersion() {
    const currentVersion = process.version
    const lowestVersion = LOWEST_NODE_VERSION
    if(!semver.gte(currentVersion, lowestVersion)) {
      throw new Error(colors.red(`zl-cli 需要安装 v${lowestVersion}以上版本的Node.js`))
    }
    
  }

  init() {
    throw new Error('init必须实现')
  }

  exec() {
    throw new Error('exec必须实现')
  }
}

module.exports = Command;
复制代码

二、初始化

参数初始化操作

 // 参数初始化操作
 chain = chain.then(() => this.initArgs())
复制代码

初始化方法

  initArgs() {
    this._cmd = this._argv[this._argv.length - 1]
    this._argv = this._argv.slice(0, this._argv.length - 1)
  }
  
复制代码

可以通过

zl-cli-dev init --targetPath F:\2021\web-jg\week2\zl-cli-dev\commands\init --debug test-project --force
复制代码

输出下this._cmd和this._argv.

同时要对参数argv做判断,判断参数不能为空,必须为数组且不能为空

 if (!argv) {
      throw new Error('参数不能为空!')
    }

    if(!Array.isArray(argv)) {
      throw new Error('参数必须为数组!')
    }

    if(argv.length < 1) {
      throw new Error('参数列表为空!')
    }
复制代码

在这里我们修改下exec/lib/index.js

try {
      // 在当前进程中使用
      require(rootFile).call(null, Array.from(arguments))
      // 在node子进程中调用
    } catch (e) {
      log.error(e.message)
    }
复制代码

使用try catch优化下输出

然后新加init和exec两个方法的调用,以及catch的监听

chain = chain.then(() => this.init())
chain = chain.then(() => this.exec())
chain.catch(err => {
  log.error(err.message)
})
复制代码

现在初始化commands/init中的方法

init() {
    this.projectName = this._argv[0] || ''
    this.force = !!this._cmd.force
    log.verbose('projectName: ' + this.projectName)
    log.verbose('force: ' + this.force)
}
复制代码

通过this._argv我们拿到了项目名称,通过this._cmd我们拿到了force的状态

导入log,我们就可以使用log.verbose了。同时创建我们的init的业务逻辑

exec() {
  console.log('init的业务逻辑')
}
复制代码

三、动态执行代码

在执行完上边的代码后,修改下之前的一块代码,exec/lib/index.js

if(rootFile) {
    try {
      // 在当前进程中使用
      // require(rootFile).call(null, Array.from(arguments))
      // 在node子进程中调用
      const code = 'console.log(1)'
      const child = cp.spawn('node', ['-e', code], {
        cwd: process.cwd(),
        stdio: 'inherit'
      })
      child.on('error', e => {
        log.error(e.message)
        process.exit(1)
      })
      child.on('exit', (e) =>{
        log.verbose('命令执行成功:'+ e)
        process.exit(e)
      })
    } catch (e) {
      log.error(e.message)
    }
   

  }
复制代码

现在我们要拼接code,动态的拼接

const args = Array.from(arguments)
const cmd = args[args.length - 1]
const o = Object.create(null)
Object.keys(cmd).forEach(key => {
  if (cmd.hasOwnProperty(key) && !key.startsWith('_') && key !== 'parent') {
     o[key] = cmd[key]
  }
})
args[args.length - 1] = o

const code = `require('${rootFile}').call(null, ${JSON.stringify(args)})`
复制代码

输入命令

zl-cli-dev init --targetPath F:\2021\web-jg\week2\zl-cli-dev\commands\init --debug --force test-project
复制代码

有一下输出就说明我们代码正常运行了!

image.png

四、windows操作系统spawn执行

方法如下

function spawn(command, args, options) {
  const win32 = process.platform === 'win'
  const cmd = win32 ? 'cmd': command
  const cmdArgs = win32 ? ['/c'].concat(command, args) : args

  return cp.spawn(cmd, cmdArgs, options || {})
}
复制代码

对windows系统做判断。替换到执行cp.spawn

 const child = spawn('node', ['-e', code], {
        cwd: process.cwd(),
        stdio: 'inherit'
      })
复制代码

再次命令,得到一下结果

image.png

成功了!!!

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享