一、ptm-cli 使用说明

  project template manager cli

  一款对项目模板/项目进行管理的脚手架工具,具有添加模板/项目编辑模板/项目删除模板/项目查看模板/项目以及下载项目根据模板初始化项目等功能。

1、特点

  • ptm-cli兼容githubgitee码云

    现在很多自行开发的脚手架都是都只能对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:想要进行编辑的模板/项目的关键信息,包括:urlbranchdelGitInfodescription

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用来捕捉克隆结果;

  • options可选参数:
  • git: git的二进制路径(可选).
  • shallow: 当为true时克隆深度为1 (可选).
  • checkout: 切换到当前分支(可选).

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,项目目录结构如下:

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包,安装完执行自定义命令有效!

Node项目模板管理脚手架ptm-cli开发的更多相关文章

  1. 运行vue项目--安装vue脚手架vue cli

    第一步. 安装node: 官网下载node的.pkg,下载地址,选择相应版本进行下载 mac终端下输入npm -v 和 node -v, 出现相应版本号即安装成功. 若均提示 command not ...

  2. 使用 DotNet CLI 创建自定义的 WPF 项目模板

    描述 当我们安装完 DotNetCore 3.0 版本的 SDK 后,我们就可以创建基于 DotNetCore 的 WPF 项目模板,通过如下 CLI 可以方便快捷的创建并运行我们的项目: dotne ...

  3. vs多项目模板及add-in开发

    本文分2部分 第一为自定义多项目模板 第二为vs add-in开发 效果图 1.自定义模板 2. 工具菜单 3.窗口 4.工程 5.文件 ... 一. 多项目模板 单项目模板做起来很简单 选中一个项目 ...

  4. 前端MVC Vue2学习总结(七)——ES6与Module模块化、Vue-cli脚手架搭建、开发、发布项目与综合示例

    使用vue-cli可以规范项目,提高开发效率,但是使用vue-cli时需要一些ECMAScript6的知识,特别是ES6中的模块管理内容,本章先介绍ES6中的基础与模块化的内容再使用vue-cli开发 ...

  5. [Vue 牛刀小试]:第十七章 - 优化 Vue CLI 3 构建的前端项目模板(1)- 基础项目模板介绍

    一.前言 在上一章中,我们开始通过 Vue CLI 去搭建属于自己的前端 Vue 项目模板,就像我们 .NET 程序员在使用 asp.net core 时一样,我们更多的会在框架基础上按照自己的开发习 ...

  6. python项目依赖管理分享迁移后重建开发环境(一)virtualenv 和 pip

    作者:Panda Fang 出处:http://www.cnblogs.com/lonkiss/p/rebuild-development-environment-with-virtualenv-an ...

  7. 分享Node.js + Koa2 + MySQL + Vue.js 实战开发一套完整个人博客项目网站

    这是个什么的项目? 使用 Node.js + Koa2 + MySQL + Vue.js 实战开发一套完整个人博客项目网站. 博客线上地址:www.boblog.com Github地址:https: ...

  8. Windows Phone 8初学者开发—第10部分:数据绑定应用程序和透视应用程序项目模板简介

    原文 Windows Phone 8初学者开发—第10部分:数据绑定应用程序和透视应用程序项目模板简介 原文地址: http://channel9.msdn.com/Series/Windows-Ph ...

  9. 后端开发实践——Spring Boot项目模板

    在我的工作中,我从零开始搭建了不少软件项目,其中包含了基础代码框架和持续集成基础设施等,这些内容在敏捷开发中通常被称为"第0个迭代"要做的事情.但是,当项目运行了一段时间之后再来反 ...

随机推荐

  1. day3(使用axios实现登录成功)

    1.创建一个login.vue页面 1.1写页面components/Login.vue 在 src/components 下创建 Login.vue 页面 <template>   &l ...

  2. 因为一个Docker问题,我顺手整理从安装到常用命令操作手册

    今天,自己写了一部分业务代码,是常规代码的另外一种方式,不能在公司的服务器上测试,就自己在PC端搭建了一套和公司集群一样的模板,因为公司的业务模块的测试有单独的服务器(这一块还是我很稀罕的),但是,第 ...

  3. PyQt信号connect连接槽方法时报:native Qt signal is not callable错误

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 在将一个信号连接到槽方法时,程序异常退出,捕获异常 ...

  4. 第11.24节 Python 中re模块的其他函数

    一. re.compile函数 正则表达式编译函数,在后面章节专门介绍. 二. re.escape(pattern) re.escape是一个工具函数,用于对字符串pattern中所有可能被视为正则表 ...

  5. [亲测可用]BCompare文件比较对比工具4.3.4绿色版

    程序员必备良品 Beyond Compare 灰常好用,一直使用的文本 文件比较工具,用来对比两个文件文本的差异,可以用于各种代码,文本对比 使用方法: 解开压缩后:添加右键的 !添加右键.bat,运 ...

  6. Python(三) PIL, Image生成验证图片

    Python(三) PIL, Image生成验证图片 安装好PIL,开始使用. 在PyCharm中新建一个文件:PIL_Test1.py 1 # PIL 应用练习 2 # 3 # import PIL ...

  7. Python(二) 安装PIL

    1. 在使用PIL之前我们需先安装PIL. 在cmd中使用 pip 指令,竟报错,没有这个指令 2. 我就给环境变量加上这个指令,找到本机上安装python的位置,找到scrips文件夹, 看到里面的 ...

  8. CF1327F AND Segments

    链接 Description 要求构造满足下列条件的长度为 \(n\) 的序列 \(a\) 的个数: 每个数值域在 \([0, 2 ^ k)\) \(m\) 个限制条件 \(l, r, x\),需要满 ...

  9. 简单的一段css代码让全站变灰,网站哀悼代码

    为表达全国各族人民对抗击新冠肺炎疫情斗争牺牲烈士和逝世通报的深切哀悼,国务院今天发布公告,决定2020年4月4日举行全国性哀悼活动.在此期间,全国和驻外使馆下半旗致哀,全国停止公共娱乐活动,4月4日1 ...

  10. Jmeter之登录接口参数化实战

    为了纪念我走过的坑(为什么有些简单的问题就是绊住我了,还是不够细啊) Jmeter之接口登录参数化实战 因为想要在登录时使用不同的数据进行测试,所以我选择了将数据进行参数化.因为涉及到新建一个接口的功 ...