我们都用过 vue 的cli ,或者 react的cli,  亦或是其他的cli 如 vite 等。他们都是提供了一个全局命令,然后在终端执行这个全局命令就可以创建出模板项目。今天我们就自己做一个,给自己用的脚手架项目,帮助自己开发一些项目。

现在我们来造点需求。

背景:我们要在nextjs 项目中,添加页面路由,用过nextjs 的同学应该知道,这个pages 下面的文件就是页面路由。我们一般添加页面都在pages文件夹下新建文件 ,有时候还会在pages同级文件夹下新建components 文件夹,来放我们页面的组件。

要求:

    1. 可以单独创建一个页面路由
    2. 如果页面复杂,那我需要在pages同级目录下创建一个components文件夹下创建同名的组件文件夹
    3. 可以控制是否生成style 文件

    分析:我们回忆下@vue/cli 这样的脚手架是如何使用的

npm install -g @vue/cli

vue create my-project

全局安装之后 开始使用这个全局命名。

那么我们就按照这个思路倒着打。

因此我们也需要搞一个全局命令,然后执行我们全局命令后,就可以执行我们想要的动作,创建文件夹,写文件等。

  1. 创建空项目,next-project-add-page
  2. npm init
  3. 修改 package.json, 添加 bin 字段
  4. 本地调试,先生成软连接 来让我们可以使用 next-add-page 命名, npm  link 
  5. 核心代码编写
{
"name": "next-project-add-page",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"bin": {
"next-add-page": "index.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"commander": "^10.0.0"
}
}

先上一个能走完大概流程的核心代码,里面一些细节的代码逻辑,我们后面再补充。

// index.js
// console.log(process.argv)
// [
// 'C:\\Program Files\\nodejs\\node.exe',
// 'C:\\Users\\Administrator\\AppData\\Roaming\\npm\\node_modules\\next-project-add-page\\index.js',
// 'add', // 想要执行的命令
// 'list', // 新增的页面
// '-components', // 是否添加到pages同级的components 文件夹下为 组件
// '-style', // 是否添加样式文件
// ]
const { program } = require('commander');
const child_process = require('child_process');
const { clearInterval } = require('timers');
const fs = require('fs');
const path = require('path');
program
.option('-components')
.option('-style'); program.parse();
console.log(program.opts()) // { Components: true, Style: true } ; function intervalProgress() {
const readline = require('readline');
const unloadChar='-';
const loadedChar='='; let i = 0;
let time = setInterval(()=>{
if(i>10){
clearInterval(time);
console.log(`创建完成,请查收`);
process.exit(0);
}
readline.cursorTo(process.stdout,0,1);
readline.clearScreenDown(process.stdout);
renderProgress('文件创建中',i);
i++;
},200); function renderProgress(text,step){
const PERCENT = Math.round(step*10);
const COUNT = 2;
const unloadStr = new Array(COUNT*(10-step)).fill(unloadChar).join('');
const loadedStr = new Array(COUNT*(step)).fill(loadedChar).join('');
process.stdout.write(`${text}:【${loadedStr}${unloadStr}|${PERCENT}%】`);
} } function main(){
if(process.argv[2] && process.argv[2] == 'add') {
if(process.argv[3]) {
// 页面名称
// 判断pages 文件夹是否存在
if(fs.existsSync(`./pages`) && !fs.existsSync(`./pages/${process.argv[3]}`)) {
let subProcess= child_process.exec("cd ./pages && mkdir " + process.argv[3], function(err,stdout){
if(err)console.log(err);
// 读取 tempalte/index.tsx 的文件
let tempalteStr = fs.readFileSync( path.resolve(__dirname, './template/index.tsx'));
fs.writeFile(`./pages/${process.argv[3]}/index.tsx`, tempalteStr, (err) =>{
console.log(err);
});
// 创建style less
if(program.opts().Style && process.argv[3]) {
fs.writeFile(`./pages/${process.argv[3]}/index.less`,'', (err) =>{
console.log(err);
});
}
subProcess.kill();
});
} }
} if(program.opts().Components && process.argv[3]) {
// 添加component组件
// 页面名称
// 判断components 文件夹是否存在
if(!fs.existsSync(`./components`)) {
fs.mkdirSync('./components');
}
if(!fs.existsSync(`./components/${process.argv[3]}`)){
let subProcess=child_process.exec("cd ./components && mkdir " + process.argv[3], function(err,stdout){
if(err)console.log(err);
subProcess.kill();
});
}
} // 展示进度条
intervalProgress();
// 精确点: 实时查询新建的几个文件(文件夹)是否创建成功,如果创建完毕,应该提前结束进度条 } main();

代码大概解说:

  • 使用nodejs 的fs 模块 api,对文件的读写以及文件存在的判断。
  • commander 对命令行的解析,得到命令行具体的值后 继续做文件的读写
  • 使用 child_process 子进程 对文件的读写
  • process.stdout.write 来写终端的输出内容
  • 用template 文件夹 放 具体的模板文件,具体生成文件的时候,可以将模板的内容给到相应的文件中
 
 
上述代码不是很复杂,一些比较细节的内容我没有做细节处理,比如进度条的展示,这里是用一个 定时器 来模拟进度的一个过程,如果需要精确点可以监听文件的生成进度,从而调优进度条的展示。
 

现在可以nextjs 项目下 执行命令:next-add-page add list -components -style

next-add-page:是全局的一个命令

add: 是添加页面的 一个命令

list: 是添加页面的名称

-components: 在 components 文件夹下创建同名的组件 (可选)

-style:  创建样式文件 (可选)

是否可选,取决与代码对这个命令行参数的解析以及操作。

现在执行这个命令行

就可以看到项目中 生成了对应的文件。

到这里基本的需求已经完成了。

接下里是发布,

具体发布到npm 的步骤就不多说了,没有发布过的可以参考下这里,https://cnodejs.org/topic/5823c4411120be9438b02a31

好了,到这里应该知道怎木去开发自己的一个cli 脚手架了。

参考

https://juejin.cn/post/6844903702453551111

https://juejin.cn/post/6857842033084760071

https://www.runoob.com/nodejs/nodejs-fs.html

搞一个自己用的node-cli的更多相关文章

  1. Node & CLI

    Node & CLI cli 生成文件的原理是什么 https://nodejs.org/api/cli.html http://nodejs.cn/api/cli.html CLI & ...

  2. 新建一个express工程,node app无反应

    1.问题描述 新建一个express工程,node app以后无反应,浏览器输入localhost:3000,显示如下 2.解决方法 在app.js文件中加入如下代码 app.listen(3000, ...

  3. 搭建一个最简单的node服务器

    搭建一个最简单的node服务器 1.创建一个Http服务并监听8888端口 2.使用url模块 获取请求的路由和请求参数 var http = require('http'); var url = r ...

  4. 打算写一个《重学Node.js》系列,希望大家多多支持

    先放上链接吧,项目已经开始2周了:https://github.com/hellozhangran/happy-egg-server 想法 现在是2019年11月24日,还有人要开始学习Node.js ...

  5. 分布式ID生成服务,真的有必要搞一个

    目录 阐述背景 Leaf snowflake 模式介绍 Leaf segment 模式介绍 Leaf 改造支持RPC 阐述背景 不吹嘘,不夸张,项目中用到ID生成的场景确实挺多.比如业务要做幂等的时候 ...

  6. how to read the system information by using the node cli tool?

    how to read the system information by using the node cli tool? node cli & get system info demos ...

  7. node cli & emoji

    node cli & emoji cli $ yarn add node-emoji $ npm i node-emoji https://github.com/omnidan/node-em ...

  8. write a node cli tools, step by step

    write a node cli tools, step by step how to write a node cli tools node cli tools, step by step, nod ...

  9. linux & node & cli & exit(0) & exit(1)

    linux & node & cli & exit(0) & exit(1) exit(0) & exit(1) demo exit(0) === OK exi ...

  10. how to write a node cli tool

    how to write a node cli tool https://www.google.com/search?q=how+to+node+cli+tool&oq=how+to+node ...

随机推荐

  1. 西瓜书6.2 matlab的libsvm使用

    因为python的教程没有找到详细的所以就改用matlab了 使用的是matlab r2016a,libsvm3-24,具体的安装配置教程就直接参考谦恭大大的了: https://blog.csdn. ...

  2. C++调用Python_____用Python C API

    项目需要用C++来处理用python处理的数据集,所以就需要在C++中调用python. 先介绍第一种方法,python文档中给出了python c api,可以实现C++与python的互动. 先新 ...

  3. pyechart画图(1)安装和基本操作

    安装 pip install pyecharts==0.1.9.4 https://blog.csdn.net/weixin_43735353/article/details/89328048 Lin ...

  4. white album句子

    1.不论是真心的笑,还是真心的生气,我都做不到.我只是个胆小的骗子.

  5. python 前言

    # python前言简介: ## 文件的概诉 ```py# 什么是文件 .文件夹? 其实是操作系统暴露给用户可以简单快捷操作硬盘的"接口"``` ## 计算机内部储存数据的原理 ` ...

  6. vue echarts 多个图表自适应

    <template> <div :id="id" :style="{width: `${width}`, height: `${height}`}&qu ...

  7. new一个实例的原理及过程

    前提,要明白new出来的实例是什么,包含了哪些内容? 请看一下举例代码↓↓↓↓ function Person(name,age){ this.name = name; this.age = age; ...

  8. 树莓派 wiringPi的BCM与BOARD编码

    一.基础命令使用wiringPi库 1.1.获取管教信息 gpio readall ---获取管脚信息   1.2.BOARD编码和BCM一般都在python库中使用 import RPi.GPIO ...

  9. 对表单input输入框加特殊符号(正斜杠和反斜杠)校验

    <p>图片名称:</p><input type="text" name="afterName" style="heigh ...

  10. Rstudio R get filename full path

    FILENAME=basename(rstudioapi::getActiveDocumentContext()$path) FULLPATH=dirname(rstudioapi::getActiv ...