第一步:创建文件夹CLI
第二步:在CLI目录终端执行名命令:npm init -y
第三步:在CLI目录下创建文件夹
创建一个bin文件夹,添加test-cli.js文件,在这个文件中写下#! /usr/bin/env node
第四步:
- 在package.json中指定执行命令和执行的文件添加bin和min目录
- { "name": "test-cli", "version": "1.0.0", "description": "", "main": "/bin/test-cli.js", "bin": "/bin/test-cli.js", "directories": { "lib": "lib" }, "scripts": { "test": "echo "Error: no test specified" && exit 1" }, "keywords": [], "author": "", "license": "ISC", }
第五步:在bin目录下执行npm link
第六步:在bin目录下执行test-cli,会输出你在test-cli文件中写下的打印信息
第七步:在package.json中添加"type": "module",然后安装所有依赖
"name": "test-cli",
"version": "1.0.0",
"description": "",
"main": "/bin/test-cli.js",
"bin": "/bin/test-cli.js",
"directories": {
"lib": "lib"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "module",
"dependencies": {
"axios": "^1.5.0",
"chalk": "^5.3.0",
"commander": "^11.0.0",
"download-git-repo": "^3.0.2",
"fs-extra": "^11.1.1",
"inquirer": "^9.2.10",
"ora": "^7.0.1",
"path": "^0.12.7",
"util": "^0.12.5"
}
}
8:新建lib文件夹,
import path from "path";
import Generator from "./creator.js";
import inquirer from "inquirer";
import fs from "fs-extra";
// 用于交互式询问用户问题
// 导出Generator类
//1. 抛出一个方法用来接收用户要创建的文件夹(项目)名 和 其他参数
const create = async function (name, options) {
// 当前命令行选择的目录
const cwd = process.cwd();
// 需要创建的目录地址
const targetAir = path.join(cwd, name);
//2 判断是否存在相同的文件夹(项目)名
// 目录是否已经存在?
if (fs.existsSync(targetAir)) {
// 是否为强制创建?
if (options.force) {
await fs.remove(targetAir);
} else {
// 询问用户是否确定要覆盖
let { action } = await inquirer.prompt([
{
name: "action",
type: "list",
message: "Target directory already exists Pick an action:",
choices: [
{
name: "Overwrite",
value: "overwrite",
},
{
name: "Cancel",
value: false,
},
],
},
]);
// 如果用户拒绝覆盖则停止剩余操作
if (!action) {
return;
} else if (action === "overwrite") {
// 移除已存在的目录
console.log(`\r\nRemoving...`);
await fs.remove(targetAir);
}
}
}
//3 新建generator类
const generator = new Generator(name, targetAir);
generator.create();
};
export default create;
import { getRepoList, getTagList } from "./request.js";
import { loading } from "./utils.js";
import downloadGitRepo from "download-git-repo";
import inquirer from "inquirer";
import chalk from "chalk";
import util from "util";
import path from "path";
class Generator {
constructor(name, targetDir) {
// 目录名称
this.name = name;
// 创建位置
this.targetDir = targetDir;
// 对 download-git-repo 进行 promise 化改造
this.downloadGitRepo = util.promisify(downloadGitRepo);
}
// 获取用户选择的模板
// 1)从远程拉取模板数据
// 2)用户选择自己新下载的模板名称
// 3)return 用户选择的名称
async getRepo() {
// 1)从远程拉取模板数据
const repoList = await loading(getRepoList, "waiting fetch template");
if (!repoList) return;
// 过滤我们需要的模板名称
const repos = repoList.map((item) => item.name);
// 2)用户选择自己新下载的模板名称
const { repo } = await inquirer.prompt({
name: "repo",
type: "list",
choices: repos,
message: "Please choose a template to create project",
});
// 3)return 用户选择的名称
return repo;
}
// 获取用户选择的版本
// 1)基于 repo 结果,远程拉取对应的 tag 列表
// 2)自动选择最新版的 tag
async getTag(repo) {
// 1)基于 repo 结果,远程拉取对应的 tag 列表
const tags = await loading(getTagList, "waiting fetch tag", repo);
if (!tags) return;
// 过滤我们需要的 tag 名称
const tagsList = tags.map((item) => item.name);
// 2)return 用户选择的 tag
return tagsList[0];
}
// 下载远程模板
// 1)拼接下载地址
// 2)调用下载方法
async download(repo, tag) {
// 1)拼接下载地址
const requestUrl = `taoTests/${repo}${tag ? "#" + tag : ""}`;
// 2)调用下载方法
await loading(
this.downloadGitRepo, // 远程下载方法
"waiting download template", // 加载提示信息
requestUrl, // 参数1: 下载地址
path.resolve(process.cwd(), this.targetDir) // 参数2: 创建位置
);
}
// 核心创建逻辑
// 1)获取模板名称
// 2)获取 tag 名称
// 3)下载模板到模板目录
// 4) 对uniapp模板中部分文件进行读写
// 5) 模板使用提示
async create() {
// 1)获取模板名称
const repo = await this.getRepo();
// 2) 获取 tag 名称
const tag = await this.getTag(repo);
// 3)下载模板到模板目录
await this.download(repo, tag);
// 5)模板使用提示
console.log(`\r\nSuccessfully created project ${chalk.cyan(this.name)}`);
console.log(`\r\n cd ${chalk.cyan(this.name)}`);
console.log(`\r\n 启动前请务必阅读 ${chalk.cyan("README.md")} 文件`);
}
}
export default Generator;
// 通过 axios 处理请求
import axios from "axios";
axios.interceptors.response.use((res) => {
return res.data;
});
/**
* 获取模板列表
* @returns Promise
*/
async function getRepoList() {
// return axios.get("https://api.github.com/orgs/geeksTest/repos");
return axios.get("https://api.github.com/orgs/taoTests/repos");
}
/**
* 获取版本信息
* @param {string} repo 模板名称
* @returns Promise
*/
async function getTagList(repo) {
return axios.get(`https://api.github.com/repos/taoTests/${repo}/tags`);
}
export { getRepoList, getTagList };
9:去github新建组织和仓库,增加tag,修改3处路径为自己的
https://api.github.com/orgs/taoTests/repos:taoTests修改为你的组织名称 https://api.github.com/repos/taoTests/${repo}/tags:taoTests修改为你的组织名称 const requestUrl = taoTests/{tag ? "#" + tag : ""};:taoTests修改为你的组织名称
可以在浏览器回车测试是否调通接口返回正确信息 此文章为9月Day08学习笔记,内容来源于极客时间《重学前端》,强烈推荐该课程