手写cli
通过命令行工具,初始化团队项目,并生成团队规范代码,一键创建项目,一键生成代码,一键生成功能模块···
解放双手,从 cli 开始, JSer 永不为奴!
创建项目目录
两种方法:
鼠标右键创建文件夹,文件夹名称即为项目名称;
打开系统命令面板(powershell、cmd···),输入命令:
mkdir 项目名称
初始化 node 项目
在项目文件目录运行命令:
npm init
运行命令后会出现如下提示(按照提示完成即可):
根据提示完成操作后,会在项目根目录生成项目描述文件package.json,可以回车跳过以下步骤,后续在package.json文件中完善项目信息。
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help init` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
package name: 项目名称
version: 版本号
description: 项目描述
entry point: (index.js)入口
test command: 测试相关
git repository: git仓库地址
keywords: 关键词
author: 作者
license: 证书
About to write to E:\***\package.json:
{
"name": "***",
"version": "***",
"description": "***",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "***",
"license": "ISC"
}
Is this OK? (yes) yes
安装相关依赖
项目后续会使用以下依赖包。
运行命令:
npm i commander download-git-repo ora handlebars figlet clear chalk open
依赖包介绍:
- commander(完整的 node.js 命令行解决方案)
- download-git-repo(从节点下载并提取仓库(GitHub, GitLab, Bitbucket))
- ora(终端进度条)
- handlebars(轻量的语义化模板)
- figlet(终端实现图形字体)
- clear(终端清屏)
- chalk(终端字符串样式)
- open(跨平台级的,可打开 url、文件、可执行脚本)
创建 cli 入口文件
项目根目录创建文件夹bin,在bin文件夹中创建mycli.js(自定义)文件。
文件内容如下:
#!/usr/bin/env node
// 第一行为约定脚本解释器以 node 进行解析,必须放在文件第一行!行首不能有任何字符!
定义执行命令
打开package.json文件,添加相关代码(句首有+号的代码为新增代码):
{
"name": "***",
"version": "***",
"description": "***",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
+ "bin": {
+ "mycli": "./bin/mycli.js"
+ },
"author": "***",
"license": "ISC",
"dependencies": {
"chalk": "^4.1.0",
"clear": "^0.1.0",
"commander": "^6.2.0",
"download-git-repo": "^3.0.2",
"figlet": "^1.5.0",
"handlebars": "^4.7.6",
"open": "^7.3.0",
"ora": "^5.1.0"
}
}
映射命令至系统
将package.json文件中刚添加的bin命令映射至系统中。
运行命令:
npm link
此时我们可以全局使用bin中的mycli命令了。
npm link机理:由于已经安装好 node 环境,故此我们可以直接全局使用node与npm命令,而npm link则是将package.json中bin下的命令通过npm与系统环境变量桥接,所以我们可以全局使用bin中的命令。
至此我们实现了 cli 的第一步:可以全局使用我们自定义的命令了~~~
莫要问我为什么在这里用了彩色的字。。。
因为我比较————
骚!
定制命令行界面
在入口文件bin => mycli.js中进行命令行界面定制。
#!/usr/bin/env node
const program = require('commander') // 引入 commander
program.version(require('../package.json').version) // 声明 cli 当前版本,如:输入mycli -V 命令,即可显示当前 cli 版本
program
.command('init <name>') // 定义使用命令,如:命令 mycli init <name>
.description('init project') // 命令描述
.action(name => { // 该命令对应的动作
console.log('init--------'+name);
})
program.parse(process.argv) // 将命令参数暴露出去,供使用者使用
定制初始化功能
在根目录中创建lib文件夹,在lib文件夹中创建init.js文件,用于编写初始化功能代码。
基础结构搭建
初始化功能基础代码结构。
lib => init.js文件代码如下:
const { promisify } = require('util') // node 核心模块 util,其中的 promisify 方法可以将异步回调方法改造成返回 Promise 实例的方法
const figlet = promisify(require('figlet')) // 以 promise 形式引入 figlet 模块,figlet 可以式代码以图形出现在终端
const clear = require('clear') // 终端清屏
const chalk = require('chalk'); // 终端字符串样式定制
const colorLog = (content, color) => console.log(chalk[color||'green'](content));// 封装日志输出,可定制颜色
module.exports = async name => {
clear();
const data = await figlet('Gisuni Welcome');
colorLog(data,'red')
}
连接功能与命令
bin => mycli.js对init方法进行引入并使用,代码如下:
#!/usr/bin/env node
const program = require('commander') // 引入 commander
program.version(require('../package.json').version) // 声明 cli 当前版本,如:输入mycli -V 命令,即可显示当前 cli 版本
program
.command('init <name>') // 定义使用命令,如:命令 mycli init <name>
.description('init project') // 命令描述
- .action(name => { // 该命令对应的动作
- console.log('init--------'+name);
- })
+ .action(require('../lib/init'))
program.parse(process.argv) // 将命令参数暴露出去,供使用者使用
下拉仓库功能
将仓库中的代码下拉至本地。
在lib文件夹中创建download.js文件,其代码如下:
const { promisify } = require('util') // node 核心模块 util,其中的 promisify 方法可以将异步回调方法改造成返回 Promise 实例的方法
module.exports.clone = async (repo, desc) => {
const download = promisify(require('download-git-repo')) // 以 promise 形式引入 download-git-repo 模块,download-git-repo 可以下拉仓库代码
const ora = require('ora') // 引入终端进度条代码
const process = ora(`下载中··· ${repo}`) // 进度条提示
process.start() // 进度条开始
await download(repo, desc) // 下拉仓库代码
process.succeed() // 进度条结束
}
引入下拉功能
将下拉功能引入至初始化模块中。
lib => init.js文件代码如下:
const { promisify } = require('util') // node 核心模块 util,其中的 promisify 方法可以将异步回调方法改造成返回 Promise 实例的方法
const figlet = promisify(require('figlet')) // 以 promise 形式引入 figlet 模块,figlet 可以式代码以图形出现在终端
const clear = require('clear') // 终端清屏
const chalk = require('chalk') // 终端字符串样式定制
const colorLog = (content, color) => console.log(chalk[color||'green'](content)) // 封装日志输出,可定制颜色
+const { clone } = require('./download') // 引入下拉功能模块
module.exports = async name => {
clear();
const data = await figlet('Gisuni Welcome');
colorLog(data,'red');
+ colorLog(`创建项目:${name}`);
+ await clone('github:用户名/项目名称', name); // 如果项目克隆地址为:https://github.com/ShanYi-Hui/react-template.git,则此处应改造为:github:ShanYi-Hui/react-template
}
自动安装依赖
下拉的项目将自动安装依赖包。
lib => init.js文件代码如下:
const { promisify } = require('util') // node 核心模块 util,其中的 promisify 方法可以将异步回调方法改造成返回 Promise 实例的方法
const figlet = promisify(require('figlet')) // 以 promise 形式引入 figlet 模块,figlet 可以式代码以图形出现在终端
const clear = require('clear') // 终端清屏
const chalk = require('chalk') // 终端字符串样式定制
const colorLog = (content, color) => console.log(chalk[color||'green'](content)) // 封装日志输出,可定制颜色
const { clone } = require('./download') // 引入下拉功能模块
+const spawn = async (...args) => {
+ const { spawn } = require('child_process') // node 核心模块 child_process,spawn 方法会异步地衍生子进程,且不阻塞 Node.js 事件循环
+ return new Promise(resolve => {
+ const proc = spawn(...args);
+ proc.stdout.pipe(process.stdout);
+ proc.stderr.pipe(process.stderr);
+ proc.on('close', () => {
+ resolve();
+ })
+ })
+}
module.exports = async name => {
clear();
const data = await figlet('Gisuni Welcome');
colorLog(data,'red');
colorLog(`创建项目:${name}`);
await clone('github:用户名/项目名称', name); // 如果项目克隆地址为:https://github.com/ShanYi-Hui/react-template.git,则此处应改造为:github:ShanYi-Hui/react-template
+ colorLog('安装依赖中···');
+ await spawn(process.platform === 'win32'?'npm.cmd':'npm', ['install'], { cwd:`./${name}` }); // 安装依赖
+ colorLog(`
+安装完成!
+
+项目将自动启动,若未启动请执行如下命令:
+==============================
+ cd ${name}
+ npm run serve
+==============================
+ `);
+}
项目自启动
依赖安装完成后将自动打开浏览器,并在指定端口(默认 8080 端口)运行服务。
lib => init.js文件代码如下:
const { promisify } = require('util') // node 核心模块 util,其中的 promisify 方法可以将异步回调方法改造成返回 Promise 实例的方法
const figlet = promisify(require('figlet')) // 以 promise 形式引入 figlet 模块,figlet 可以式代码以图形出现在终端
const clear = require('clear') // 终端清屏
const chalk = require('chalk') // 终端字符串样式定制
const colorLog = (content, color) => console.log(chalk[color||'green'](content)) // 封装日志输出,可定制颜色
const { clone } = require('./download') // 引入下拉功能模块
+const open = require('open') // 打开链接
const spawn = async (...args) => {
const { spawn } = require('child_process') // node 核心模块 child_process,spawn 方法会异步地衍生子进程,且不阻塞 Node.js 事件循环
return new Promise(resolve => {
const proc = spawn(...args);
proc.stdout.pipe(process.stdout); // 子进程中的日志通过管道传输至主进程
proc.stderr.pipe(process.stderr); // 子进程中的错误捕获通过管道输出至主进程
proc.on('close', () => { // 关闭子进程
resolve(); // promise 状态切换至执行完成状态
})
})
}
module.exports = async name => {
clear();
const data = await figlet('Gisuni Welcome');
colorLog(data,'red');
colorLog(`创建项目:${name}`);
await clone('github:用户名/项目名称', name); // 如果项目克隆地址为:https://github.com/ShanYi-Hui/react-template.git,则此处应改造为:github:ShanYi-Hui/react-template
colorLog('安装依赖中···');
await spawn(process.platform === 'win32'?'npm.cmd':'npm', ['install'], { cwd:`./${name}` }); // 安装依赖
colorLog(`
安装完成!
项目将自动启动,若未启动请执行如下命令:
==============================
cd ${name}
npm run serve
==============================
`);
+ open('http://localhost:8080'); // 打开指定端口
+ await spawn(process.platform === 'win32'?'npm.cmd':'npm', ['run','serve'], { cwd:`./${name}` }); // 启动项目
}
其实到这里,一个最基本的 cli 已经制作完成了~~~
那么接下来将开始丰富它的功能!
更新中···
手写cli的更多相关文章
- 【Win 10 应用开发】手写识别
记得前面(忘了是哪天写的,反正是前些天,请用力点击这里观看)老周讲了一个14393新增的控件,可以很轻松地结合InkCanvas来完成涂鸦.其实,InkCanvas除了涂鸦外,另一个大用途是墨迹识别, ...
- JS / Egret 单笔手写识别、手势识别
UnistrokeRecognizer 单笔手写识别.手势识别 UnistrokeRecognizer : https://github.com/RichLiu1023/UnistrokeRecogn ...
- 如何用卷积神经网络CNN识别手写数字集?
前几天用CNN识别手写数字集,后来看到kaggle上有一个比赛是识别手写数字集的,已经进行了一年多了,目前有1179个有效提交,最高的是100%,我做了一下,用keras做的,一开始用最简单的MLP, ...
- 【转】机器学习教程 十四-利用tensorflow做手写数字识别
模式识别领域应用机器学习的场景非常多,手写识别就是其中一种,最简单的数字识别是一个多类分类问题,我们借这个多类分类问题来介绍一下google最新开源的tensorflow框架,后面深度学习的内容都会基 ...
- caffe_手写数字识别Lenet模型理解
这两天看了Lenet的模型理解,很简单的手写数字CNN网络,90年代美国用它来识别钞票,准确率还是很高的,所以它也是一个很经典的模型.而且学习这个模型也有助于我们理解更大的网络比如Imagenet等等 ...
- 使用神经网络来识别手写数字【译】(三)- 用Python代码实现
实现我们分类数字的网络 好,让我们使用随机梯度下降和 MNIST训练数据来写一个程序来学习怎样识别手写数字. 我们用Python (2.7) 来实现.只有 74 行代码!我们需要的第一个东西是 MNI ...
- 手写原生ajax
关于手写原生ajax重要不重要,各位道友自己揣摩吧, 本着学习才能进步,分享大家共同受益,自己也在自己博客里写一下 function createXMLHTTPRequest() { //1.创建XM ...
- springmvc 动态代理 JDK实现与模拟JDK纯手写实现。
首先明白 动态代理和静态代理的区别: 静态代理:①持有被代理类的引用 ② 代理类一开始就被加载到内存中了(非常重要) 动态代理:JDK中的动态代理中的代理类是动态生成的.并且生成的动态代理类为$Pr ...
- 为sproto手写了一个python parser
这是sproto系列文章的第三篇,可以参考前面的<为sproto添加python绑定>.<为python-sproto添加map支持>. sproto是云风设计的序列化协议,用 ...
随机推荐
- Java知识系统回顾整理01基础03变量06变量的作用域
一.变量根据所处的位置对应不同的名称 变量处于不同的位置,有不同的名称 名称分别是 字段,属性 参数 局部变量 不同名称的变量,其作用域是不一样的 二.字段,属性,Field 当一个变量被声明在类下 ...
- 【学习笔记/题解】分层图/[JLOI2011]飞行路线
题目戳我 \(\text{Solution:}\) 关于分层图: 一般用于处理:给你\(k\)次机会对边权进行修改的最短路问题. 算法流程: 建立出\(k\)层图,对应进行\(k\)次操作后的局面. ...
- 安装 Windows 10 系统时分区选择 MBR 还是 GUID?
一.MBR 和 GUID 的概述 MBR 分区表 MBR:Master Boot Record,即硬盘主引导记录分区表,指支持容量在2.1TB以下的硬盘,超过2.1TB的硬盘只能管理2.1TB,最多只 ...
- Flink深入浅出: 资源管理(v1.11)
-- 图片来自 <国家地理中文网>-- 往期推荐: Flink深入浅出:部署模式 Flink深入浅出:内存模型 Flink深入浅出:JDBC Source从理论到实战 Flink深入浅出: ...
- OAuth 2.0 Server PHP实现示例
需求实现三方OAuth2.0授权登录 使用OAuth服务OAuth 2.0 Server PHP 环境nginx mysqlphp 框架Yii 一 安装 项目目录下安装应用 composer.phar ...
- antd pro 下的文件下载
概要 示例 后端 前端 直接显示图片 提供下载链接, 点击后下载 文件导出, 前端没有显示下载链接的位置 概要 前端上传文件的例子很多, 但是下载相关的例子不多, 主要是因为下载本身比较简单. 但是这 ...
- 实验二 C2C实践
实验二 C2C实践 [实验目的] 掌握网上购物的基本流程和C2C平台的运营 [实验条件] ⑴.个人计算机一台 ⑵.计算机通过局域网形式接入互联网. (3).奥派电子商务应用软件 [知识准备] 本实验 ...
- 动画演示Sunday字符串匹配算法——比KMP算法快七倍!极易理解!
前言 上一篇我用动画的方式向大家详细说明了KMP算法(没看过的同学可以回去看看). 这次我依旧采用动画的方式向大家介绍另一个你用一次就会爱上的字符串匹配算法:Sunday算法,希望能收获你的点赞关注收 ...
- 第六章 Linux系统之文件管理
一.文件管理概述 1.对文件做些什么? 谈到Linux文件管理,首先我们需要了解的就是,我们要对文件做些什么事情? 其实无非就是对一个文件进行创建.复制.移动.查看.编辑.压缩.查找.删除等等 2.内 ...
- 小C和小派的缠绵爱情——C语言调用Python代码
我妒忌你的开源,你眼红我的速度,不如我们就在一起吧! --------SJ2050 2019.4.9号更新:实现在未安装python环境的机子上运行调用了python程序的C语言代码! 文章目录 环境 ...