项目模板管理脚手架ptm-cli开发
码农天地 -一、ptm-cli 使用说明
project template manager cli
一款对项目模板/项目进行管理的脚手架工具,具有添加模板/项目
、编辑模板/项目
、删除模板/项目
、查看模板/项目
以及下载项目
和根据模板初始化项目
等功能。
github
和gitee码云
:现在很多自行开发的脚手架都是都只能对github上模板/项目进行下载(底层使用download-git-repo
),随着国内码云的发展壮大,国内开发者很多也在码云上进行代码管理,兼容gitee也十分必要;目前现有的脚手架轮子中并没有兼容码云的!
大多数脚手架只对某一个模板进行初始化下载,只具备指定初始化功能;ptm-cli能够对模板和项目进行管理
,不仅可以自由添加删除开源的优秀项目
(例如vue),还可以添加删除编辑自己开发的项目模板
;
$ 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);···commander详细api
2)inquirer处理可交互
的node.js嵌入式的命令行界面
的第三方npm库。
常用API:
声明 inquirer 变量const inquirer = require('inquirer');具体使用方式inquirer.prompt([
/ 放入可交互式提供的问题 /
])
.then(answers => {
// 命令行中接收到的输入参数
})
.catch(error => {
// 报错获取
});···
inquirer详细api
3)git-clone通过shell命令克隆
一个git存储库
的第三方npm库。
常用API:
声明 git-clone 变量const clone = require('git-clone');具体使用方式clone(repo, targetPath, [options], cb);
克隆一个repo路径的git仓库到targetPath目录下,回调函数cd用来捕捉克隆结果;
git-clone详细api
4)chalk改变终端输出样式
的第三方npm库。
常用API:
声明 chalk 变量const chalk = require('chalk');具体使用方式console.log(chalk.blue('Hello world!'));chalk详细api
5)ora添加优雅的终端转轮
的第三方npm库。
常用API:
声明 ora 变量const ora = require('ora');具体使用方式const spinner = ora('提示内容···');开始显示转轮spinner.start()错误/失败显示转轮spinner.fail()成功转轮显示spinner.succeed()···ora详细api
6)rimraf封装rm -rf
命令,用来删除文件和文件夹
的第三方npm库。
常用API:
声明 rimraf 变量const rm = require("rimraf").sync;具体使用方式,删除指定file文件/文件夹rm(file, [opts], callback)···rimraf详细api
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
,项目目录结构如下:
在上述新建bin目录
下的6个功能文件
最上方添加#!/usr/bin/env node
:配置#!/usr/bin/env node, 就是解决了不同系统node路径不同,让系统动态的去查找node来执行你的脚本文件。
当用户不了解ptm-cli时,输入ptm可以向用户展示可用的所用命令语句和含义(commander
);
#!/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
);
#!/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包,安装完执行自定义命令有效!