前端脚手架搭建

1,260 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第12天,点击查看活动详情

初始化项目

1.创建项目

mkidr cli-build
cd cli-build
npm init -y

2.创建入口文件

// bin/index.js
#!/usr/bin/env node

console.log('hello')

3.编写命令

"bin": {
    "cli-build": "./bin/index.js"
  },

4.本地软链

npm link

检查Node版本

1.新建lib目录,所有工具都放在这里

2.在lib目录下创建checkNode.js

const semver = require('semver')
module.exports = function checkNode(minNodeVersion){
    // 获取当前node版本
    const nodeVersion = semver.valid(semver.coerce(process.version))
    return semver.satisfies(nodeVersion, '>='+minNodeVersion)
}

3.在bin/index.js中引入并使用

#!/usr/bin/env node

const { program } = require('commander')
const pkg = require('../package.json')
const checkNode = require('../lib/checkNode')

const MIN_NODE_VERSION = '8.9.0'

(async () => {

    try{
        if(!checkNode(MIN_NODE_VERSION)){
            throw new Error('Please upgrade your node version to v' + MIN_NODE_VERSION)
        }
    }catch(e){
        console.log(e.message)
    }
})()

命令注册

#!/usr/bin/env node

const { program } = require('commander');
const pkg = require('../package.json');
const checkNode = require('../lib/checkNode');
const startServer = require('../lib/start/startServer')
const buildServer = require('../lib/build/buildServer')

const MIN_NODE_VERSION = '8.9.0';

try {
  if (!checkNode(MIN_NODE_VERSION)) {
    throw new Error('Please upgrade your node version to v' + MIN_NODE_VERSION);
  }

  program.version(pkg.version)

  program
    .command('start')
    .description('start server by cli-build ')
    .allowUnknownOption()
    .action(startServer)

    program
    .command('build')
    .description('build project by cli-build')
    .allowUnknownOption()
    .action(buildServer)

  program.parse(process.argv)
} catch (e) {
  console.log(e.message);
}

测试下start命令

测试下build命令

start命令

1.安装文件监听第三方库

npm i -S chokidar

2.config文件监听

function onChange() {
  console.log('change')
}

function runWatcher() {
  // 启动配置监听服务
  const configPath = path.resolve(__dirname, './config.json');
  const watcher = chokidar
    .watch(configPath)
    .on('change', onChange)
    .on('error', (error) => {
      console.error(error);
      process.exit(1);
    });
}

3.start服务在另外子进程进行

// 启动子进程
  console.log('pid', process.pid)
  const scriptPath = path.resolve(__dirname,'./DevService.js')
  const child = cp.fork(scriptPath)
  child.on('message',data => {

  })

4.子进程运行脚本获取默认端口号

const DEFAULT_PORT = 8000;
const params = process.argv.slice(2);
const paramObj = {};
params.forEach(param => {
    const paramsArr = param.split(' ')
    paramObj[paramsArr[0].replace('--','')] = paramsArr[1]
})

let defaultPort = paramObj['port'] || DEFAULT_PORT;
defaultPort = parseInt(defaultPort,10)

5.判断默认端口号是否被占用

使用detect-port第三方库

const detect = require('detect-port');

try{
        const newPort = await detect(defaultPort)
        if(newPort === defaultPort){
            console.log(`端口号 ${defaultPort} 可以使用`)
        }else{
            console.log(`端口号 ${defaultPort} 被占用,建议使用新端口号:${newPort}`)
        }
    }catch(e){
        console.error(e)
    }

6.让用户通过交互式选择端口号

使用inquirer第三方库

try{
        const newPort = await detect(defaultPort)
        if(newPort === defaultPort){
            console.log(`端口号 ${defaultPort} 可以使用`)
        }else{
            // 命令行交互
            const questions = {
                type: 'list',
                name: 'answer',
                message:`${defaultPort}端口号已被占用,是否启用新端口号 ${newPort}?`,
            };
            const { answer } = await inquirer.prompt(questions)
            if(!answer){
                process.exit(1)
            }
        }
    }catch(e){
        console.error(e)
    }

7.实现配置文件修改后服务自动重启

当用户选择不使用新端口的时候,需要将主进程也退出

// 主进程退出
  child.on('exit', code => {
    if(code){
      process.exit(code)
    }
  })

当修改配置文件的时候,先关闭子进程,然后重启子进程

function onChange() {
  // 关闭子进程
  child.kill()

  // 重新启动子进程
  runServer()
}