我们都用过 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. python + appium 常用公共方法封装

    appium 程序下载安装见之前的帖子:https://www.cnblogs.com/gancuimian/p/16536322.html appium 环境搭建见之前的帖子:https://www ...

  2. limit资源限制ulimit 详解

    系统性能一直是一个受关注的话题,如何通过最简单的设置来实现最有效的性能调优,如何在有限资源的条件下保证程序的运作,ulimit 是我们在处理这些问题时,经常使用的一种简单手段.ulimit 是一种 L ...

  3. matlab读写文件

    dsp,fpga这些产生的文件大部分都是二进制存储的,知道格式后可以直接读取. 读取后的"可懂"数据如何以"可懂"的形式保存在.dat,.txt,.csv之类文 ...

  4. kafka例子

    <dependencies> <dependency> <groupId>org.apache.kafka</groupId> <artifact ...

  5. JAVA框架入门理解

    一:关于java开发的框架我们可以先从java web开发框架的变迁来给大家简单叙述一下: 1 SSH --Struts+Spring+Hibernate 2 Spring +SpringMVC + ...

  6. C# core 最简单的方式写入日志

    System.IO.StreamWriter sw = System.IO.File.AppendText( LogPath + LogFielPrefix + "Error-" ...

  7. Android studio Internet跳转活动

    <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android=" ...

  8. puts()与scanf(“%s”)

    使用gets()即使字符串中含有空格,依然可以接收,而scanf()不会. Example: /* 输入一个字符串到字符数组s1中,将s1中的字符串复制到字符数组s2中并输出s2中的字符串. 不用st ...

  9. [CQOI2014]通配符匹配 题解

    第一眼:什么鬼东西ヾ(。`Д´。) 第二眼:显然,这道题要分段处理 类似[TJOI2018]碱基序列\ (建议做一做也是Hash+DP)\ 那你怎么第一眼没看出来 Hash处理+DP==AC 直接上代 ...

  10. jsp第10个作业

    package Servlet; import JDBC.JDBC; import javax.servlet.ServletException; import javax.servlet.annot ...