一、ptm-cli 使用说明
project template manager cli
一款对项目模板/项目进行管理的脚手架工具,具有添加模板/项目
、编辑模板/项目
、删除模板/项目
、查看模板/项目
以及下载项目
和根据模板初始化项目
等功能。
1、特点
-
ptm-cli兼容
github
和gitee码云
:现在很多自行开发的脚手架都是都只能对github上模板/项目进行下载(底层使用
download-git-repo
),随着国内码云的发展壮大,国内开发者很多也在码云上进行代码管理,兼容gitee也十分必要;目前现有的脚手架轮子中并没有兼容码云的! -
管理功能全:
大多数脚手架只对某一个模板进行初始化下载,只具备指定初始化功能;ptm-cli能够对
模板和项目进行管理
,不仅可以自由添加删除开源的优秀项目
(例如vue),还可以添加删除编辑自己开发的项目模板
;
2、安装
$ npm install ptm-cli -g
3、使用
1)基础帮助命令
安装完在电脑终端输入相应命令查看和执行相关操作。
# 查看脚手架可执行的相关命令语句
$ ptm
# 查看当前版本
$ ptm -V
# 查看帮助
$ ptm -h
2)添加模板/项目
输入命令:
$ ptm-add
根据终端提示输入相关信息:
模板名:添加的模板
自定义命名
(建议使用引文);url:模板/项目在
github
或者码云
上的https
/ssh
克隆地址链接;branch:模板/项目所在github或者码云上的
分支名
(默认master);delGitInfo:是否删除模板/项目中的
原作者git的开发信息
(默认true删除),对于模板管理建议默认设置为true,即初始化模板不含有其他让人的git信息,对于项目管理(自己项目)建议保留自己开发相关的git信息;description:模板/项目的描述信息(默认为空);
例子:
xxx % ptm-add
? 请输入模板名称 vpblogs
? 请输入模板地址(https/ssh) git@gitee.com:goodloving/vpblogs.git
? 请输入模板分支(默认master) master
? 是否删除模板中.git信息(默认删除) true
? 请输入模板描述(默认为空) 基于vuepress创建个人博客主页的模板工程
添加模板成功!
最终的模板列表为:
vpblogs
url:git@gitee.com:goodloving/vpblogs.git
branch:master
description:基于vuepress创建个人博客主页的模板工程
delGitInfo:true
xxx %
3)编辑模板/项目
输入命令:
$ ptm-edit templateName key content
根据终端提示输入相关信息:
templateName:本人
添加过的模板/项目名
;key:想要进行编辑的模板/项目的
关键信息
,包括:url、branch、delGitInfo、description;content:对关键字对应
内容进行编辑替代
的内容;
例子(修改模板vpblogs的delGitInfo信息):
xxx % ptm-edit vpblogs delGitInfo false
修改模板成功!
最终的模板列表为:
vpblogs
url:git@gitee.com:goodloving/vpblogs.git
branch:master
description:基于vuepress创建个人博客主页的模板工程
delGitInfo:false
xxx %
4)查看模板/项目
输入命令:
$ ptm-list
例子:
xxx % ptm-list
模板列表为:
vpblogs
url:git@gitee.com:goodloving/vpblogs.git
branch:master
description:基于vuepress创建个人博客主页的模板工程
delGitInfo:false
xxx %
5)删除模板/项目
输入命令:
$ ptm-del
例子:
xxx % ptm-del
? 请输入要删除的模板名称 vpblogs
删除模板成功!
最终的模板列表为:
xxx %
6)基于模板新建/初始化项目
输入命令:
$ ptm-init vpblogs testPTM
例子(根据模板vpblogs新建项目testPTM):
xxx % ptm-init vpblogs testPTM
开始创建项目~
✔ 正在创建中···
项目创建成功~
开始你的项目开发!
xxx %
执行完成后在当前终端所在目录
下可以看到名为testPTM
的项目文件!
二 ptm-cli
脚手架开发
1、知识储备
1)commander
完整的node.js 命令行解决方案
,用来处理终端命令行中输入命令和编写命令行指令的第三方npm库。
常用API:
- 声明 program 变量
const { program } = require('commander');
- 命令行输出版本号
program.version('0.0.1');
- 命令行输出指令提示
program.usage("<command> [Options]");
- 命令行输出单一命令输入规范提示
program.command("ptm-add", "新增一个模板库!")
- 解析命令行参数
program.parse(process.argv);
- ···
2)inquirer
处理可交互
的node.js嵌入式的命令行界面
的第三方npm库。
常用API:
- 声明 inquirer 变量
const inquirer = require('inquirer');
- 具体使用方式
inquirer
.prompt([
/* 放入可交互式提供的问题 */
])
.then(answers => {
// 命令行中接收到的输入参数
})
.catch(error => {
// 报错获取
});
- ···
3)git-clone
通过shell命令克隆
一个git存储库
的第三方npm库。
常用API:
- 声明 git-clone 变量
const clone = require('git-clone');
- 具体使用方式
clone(repo, targetPath, [options], cb);
克隆一个repo路径的git仓库到targetPath目录下,回调函数cd用来捕捉克隆结果;
- options可选参数:
- git: git的二进制路径(可选).
- shallow: 当为true时克隆深度为1 (可选).
- checkout: 切换到当前分支(可选).
4)chalk
改变终端输出样式
的第三方npm库。
常用API:
- 声明 chalk 变量
const chalk = require('chalk');
- 具体使用方式
console.log(chalk.blue('Hello world!'));
5)ora
添加优雅的终端转轮
的第三方npm库。
常用API:
- 声明 ora 变量
const ora = require('ora');
- 具体使用方式
const spinner = ora('提示内容···');
- 开始显示转轮
spinner.start()
- 错误/失败显示转轮
spinner.fail()
- 成功转轮显示
spinner.succeed()
- ···
6)rimraf
封装rm -rf
命令,用来删除文件和文件夹
的第三方npm库。
常用API:
- 声明 rimraf 变量
const rm = require("rimraf").sync;
- 具体使用方式,删除指定file文件/文件夹
rm(file, [opts], callback)
- ···
2、初始化项目
新建项目文件夹PTM_CLI
,在项目文件夹下打开终端执行初始化操作npm init
,与终端进行交互操作生成含有项目信息的package.json
文件,依次安装步骤1
中的6个
要用到的第三方npm库:npm install xxx -g
(也可直接将依赖写入package.json
中的dependences
中,直接执行npm install
);
打开package.json
文件,添加终端命令执行语句(bin
区域下):
{
"name": "ptm-cli",
···
"private": false,
"author": {
"name": "wawoweb",
"wechat(公众号)": "wawoweb / 哇喔WEB",
"wechat": "h17179797429",
"email": "936106161@qq.com"
},
"bin": {
"ptm": "./bin/ptm.js",
"ptm-init": "./bin/ptm-init.js",
"ptm-list": "./bin/ptm-list.js",
"ptm-add": "./bin/ptm-add.js",
"ptm-del": "./bin/ptm-del.js",
"ptm-edit": "./bin/ptm-edit.js"
},
···
"dependencies": {
"chalk": "^4.1.0",
"commander": "^6.2.1",
"git-clone": "^0.1.0",
"inquirer": "^7.3.3",
"ora": "^5.1.0",
"rimraf": "^3.0.2"
}
}
同时,在项目文件夹下新建目录bin
,并在bin文件夹下新建package.json
中对应的6个文件:
./bin/ptm.js 终端命令ptm执行文件
./bin/ptm-init.js 终端命令ptm-init执行文件(根据模板初始化项目)
./bin/ptm-list.js 终端命令ptm-list执行文件(查看当前模板列表)
./bin/ptm-add.js 终端命令ptm-add执行文件(添加新的模板)
./bin/ptm-del.js 终端命令ptm-del执行文件(删除指定模板)
./bin/ptm-edit.js 终端命令ptm-edit执行文件(编辑指定模板指定信息内容)
最后在根目录下新建模板存储文件template.json
,项目目录结构如下:
3、功能开发
在上述新建bin目录
下的6个功能文件
最上方添加#!/usr/bin/env node
:配置#!/usr/bin/env node, 就是解决了不同系统node路径不同,让系统动态的去查找node来执行你的脚本文件。
1)ptm(脚手架命令提示)
分析:
当用户不了解ptm-cli时,输入ptm可以向用户展示可用的所用命令语句和含义(commander
);
代码(ptm.js):
#!/usr/bin/env node
const program = require("commander");
const package = require("../package.json");
// 定义当前版本
// 定义使用方法
// 定义五个指令
program
.version(package.version)
.usage("<command> [Options]")
.command("ptm-add", "新增一个模板库!")
.command("ptm-del", "删除一个模板库!")
.command("ptm-list", "查看模板库列表!")
.command("ptm-edit templatename key content", "修改模板库信息!")
.command("ptm-init templatename projectName", "基于模板库创建一个新的工程!");
// 解析命令行参数
program.parse(process.argv);
2)ptm-add(添加模板)
分析:
将用户指定模板添加到template.json中存储起来,需要与用户进行交互(inquirer
),涉及到文件的读写(fs
),将执行结果向用户展示(chalk
);
代码(ptm-add.js):
#!/usr/bin/env node
//交互式命令行库
const inquirer = require("inquirer");
//控制台样式库
const chalk = require("chalk");
//node内置文件模块库
const fs = require("fs");
//读取模板配置文件
const tpConfig = require(`${__dirname}/../template.json`);
// 打印模板列表的公共函数
const printPtmList = require("../utils").printPtmList;
//自定义交互式命令行的问答
let questions = [
{
name: "name",
type: "input",
message: "请输入模板名称",
validate(val) {
if (val === "") {
return "模板名不能为空!";
} else if (tpConfig[val]) {
return "模板名已经存在!";
} else {
return true;
}
},
},
{
name: "url",
type: "input",
message: "请输入模板地址(https/ssh)",
validate(val) {
if (val === "") return "模板地址不能为空!";
return true;
},
},
{
name: "branch",
type: "input",
message: "请输入模板分支(默认master)",
default: "master",
},
{
name: "delGitInfo",
type: "input",
message: "是否删除模板中.git信息(默认删除)",
default: true,
},
{
name: "description",
type: "input",
message: "请输入模板描述(默认为空)",
default: "",
},
];
inquirer.prompt(questions).then((answers) => {
// 获取用户输入的内容
let { name, url, branch, description, delGitInfo } = answers;
//过滤Unicode的字符
tpConfig[name] = {
url,
branch,
description,
delGitInfo,
};
// 将模板信息写入template.json文件中s
fs.writeFile(
`${__dirname}/../template.json`,
JSON.stringify(tpConfig),
"utf-8",
(err) => {
if (err) {
console.log(chalk.red(`\n添加模板失败:${err}\n`));
} else {
console.log(chalk.green("\n添加模板成功!\n"));
console.log("最终的模板列表为:");
printPtmList(tpConfig);
}
}
);
});
模板列表打印函数封装(utils.js):
const chalk = require("chalk");
const printPtmList = (tpConfig) => {
//遍历模板展示出来
for (const key in tpConfig) {
if (tpConfig.hasOwnProperty(key)) {
const item = tpConfig[key];
console.log(chalk.blue(` ${key}`));
for (const i in item) {
if (item.hasOwnProperty.call(item, i)) {
const el = item[i];
console.log(chalk.blue(` ${i}:${el}`));
}
}
}
}
};
module.exports = {
printPtmList
};
3)ptm-list、ptm-del、ptm-edit
分析:
- ptm-list:读取template.json文件(fs),对json格式数据输出打印(chalk);
- ptm-del:读取template.json文件(fs),与用户交互(inquirer),删除指定模板信息,输出删除后结果(chalk)
- ptm-edit:读取template.json文件(fs),与用户交互(inquirer),指定模板的信息进行修改(commander),输出最终修改结果(chalk);
代码简单(省略)
4)ptm-init(根据模板初始化项目)
分析:
提示用户ptm-init
命令必须的参数设置,对输入参数进行判断
,读取template.json
信息提取新建项目基于的模板信息,从github
或者gitee(码云)
上clone git库
文件,根据配置中要求判断是否删除原作者的git开发信息
,输出init结果
!
代码
ptm-init.js
#!/usr/bin/env node
const program = require("commander");
const chalk = require("chalk");
const ora = require("ora");
const gitclone = require("git-clone");
const tpConfig = require(`${__dirname}/../template`);
const rm = require("rimraf").sync;
program.usage("templatename projectName").parse(process.argv);
//判断输入情况
if (program.args.length < 1) {
return program.help();
}
//输入参数提取
let templateName = program.args[0];
let projectName = program.args[1];
//参数校验
if (!tpConfig[templateName]) {
console.log(chalk.red("当前模板不存在!\n"));
return;
}
if (!projectName) {
console.log(chalk.red("新建项目名不能为空! \n"));
return;
}
let temp = tpConfig[templateName];
//提取模板的url
let url = temp.url;
//提取分支
let branch = temp.branch;
console.log(chalk.greenBright("\n开始创建项目~ \n"));
//显示加载图标
const spinner = ora("正在创建中···");
spinner.start();
//下载所需额外参数
let cloneOptions = {
checkout: branch,
shallow: branch === "master",
};
// 下载git上模板代码
gitclone(url, projectName, cloneOptions, (err) => {
if (err) {
spinner.fail();
console.log(chalk.red(`\n创建项目失败:${err}\n`));
} else {
if (temp.deldelGitInfo) {
// 删除.git相关文件
rm(projectName + "/.git");
}
//成功
spinner.succeed();
console.log(chalk.green("\n项目创建成功~ \n"));
console.log(chalk.green("开始你的项目开发!"));
}
});
4、npm发布
-
1)确认package.json中npm发布内容是否完善正确
- "name": "ptm-cli", //发布到npm上的库的名字
- "version": "1.0.0", //当前发布版本号(x.y.z格式规定:x大的版本号,大版本号不同代表不向下兼容;y小版本号,当前版本较大改动,向下兼容;z代码较小改动或者bug修改)
- "description": "", //npm库的简要描述
- "private": false, //是否公开设置
- "keywords": [], //npm上搜索的关键词设置
- ···
-
2)npm登录和发布
- 去npm网站注册账号;
- 终端输入
npm login
,根据提示输入用户名、密码、邮箱; - 终端输入
npm publish
发布,查看结果是否发布成功; - 强制撤回24小时内发布的npm库,输入
npm unpublish --force
;
-
3)npm发布验证
- 在npm网站搜索中输入发布的npm库名,能够搜索到说明已经发布成功!
- 本地下载验证
打开本地终端输入npm install ptm-cli -g
下载安装发布的npm包,安装完执行自定义命令有效!