持续创作,加速成长!这是我参与「掘金日新计划 · 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()
}