cc-cli-app
v1.0.1
Published
脚手架开发
Downloads
1
Readme
日常开发中,你们是怎么样来统一自己的前端基础架构的呢?目前我们公司还是在 gitlab 上建一个基础的模板仓库,然后再 clone 到本地进行开发,这样的话仓库可能要关联多个 git 远程,万一操作失误可就难办了,而且也没有办法做一些定制化的设定。
接下来,几分钟让你掌握打造一个类似于 vue-cli、create-react-app 的脚手架工具,每次开发新项目直接 init 一下就好啦!
1. 项目初始化
首先,创建文件夹,包名自定义,这里我新建文件夹 cc-cli-app
cd cc-cli-app
pnpm init
init 后根目录创建包 bin,新建文件 index.js
修改 package.json 文件,添加
{
...,
"type": "module",
"bin":{
//这里的cc-cli可以换成任何你自己想设定的npm命令 注意别和其他冲突即可
"cc-cli": "./bin/index.js"
}
}
2. 安装相关插件
这里我们直接一次性安装所有需要的包
pnpm add command-line-args command-line-usage chalk prompts ora download-git-repo
3. 编写脚本
首先,我们先定义执行环境,以及 npm link 下方便调试
在 bin 下的 index.js 输入如下
#! /usr/bin/env node
console.log("hello cli");
终端执行
npm link
之后我们在终端输入 cc-cli,会发现 hello cli 输出出来了
(这里的 cc-cli 是你在 package.json 中定义的指令,后续不再重复)
在 bin/index.js 引入之前安装的包
import commandLineArgs from "command-line-args";
import commandLineUsage from "command-line-usage";
import chalk from "chalk";
import prompts from "prompts";
import ora from "ora";
import download from "download-git-repo";
import fs from "fs";
接下来,一个个告诉你这些作用都是什么
commandLineArgs
通过预设一些参数,让我们能正常的接收到期望得到的数据进行后续处理
const argOptions = [
{ name: "version", alias: "v", type: Boolean },
{ name: "name", type: String },
{ name: "age", type: Number },
];
console.log(commandLineArgs(argOptions));
这时,执行的命令后面加上 --[name] 参数
若在预设的 options 内,则会正确打印,否则抛出错误
commandLineUsage
commandLineUsage 可以添加帮助说明,让其他不熟悉我们脚手架的小伙伴尽快上手。 这里我们继续修改 bin/index.js
const argOptions = [
{ name: "help", alias: "h", type: Boolean },
{ name: "version", alias: "v", type: Boolean },
{ name: "name", type: String },
{ name: "age", type: Number },
];
const helpSections = [
{
header: "cc-cli",
content: "一个快速生成开发环境的脚手架",
},
{
header: "Options",
optionList: [
{
name: "version",
typeLabel: "{underline boolean}",
description: "版本号",
},
{
name: "name",
typeLabel: "{underline string}",
description: "姓名",
},
{
name: "age",
typeLabel: "{underline number}",
description: "年龄",
},
],
},
];
const options = commandLineArgs(argOptions);
if (options.help) {
console.log(commandLineUsage(helpSections));
}
关键内容
剩下的几个插件这里简单介绍下,接下来在代码中会更好地体现 chalk:自定义终端输出文本的颜色,比如 log 的内容包上 chalk.green(xxx),输出的则是绿色的文本啦 prompts:可以对我们脚手架做一些自定义的设置,类似 vue-cli 初始化时设置是否需要 ts、router 这样 download-git-repo: 下载远程 git 仓库到本地 ora:在下载时提供 loading 展示
这里,我们首先配置下在初始化项目时需要进行哪些设定
// 更多type设置可去prompts文档查看
const promptsOptions = [
{
type: "text", // 输入
name: "name",
message: "项目名称",
validate(val) {
if (!val) return "模板名称不能为空!";
if (fs.existsSync(val)) return "项目名已存在";
if (val.match(/[^A-Za-z0-9\u4e00-\u9fa5_-]/g))
return "模板名称包含非法字符,请重新输入";
return true;
},
},
{
type: "select", // 单选
name: "template",
message: "选择来源",
choices: [
{ title: "gitee", value: 1 },
{ title: "github", value: 2 },
],
},
];
const getInputInfo = async () => {
const res = await prompts(promptsOptions);
console.log(res);
};
getInputInfo();
打印输入的结果返回
那么接下来,我们可以根据返回的结果做一些自定义的处理 比如说下载远程仓库
首先编写 gitClone 函数
const gitClone = (remote, name, option) => {
// 这里通过ora开启loading状态
const downSpinner = ora("正在下载模板...").start();
return new Promise((resolve, reject) => {
download(remote, name, option, (err) => {
if (err) {
downSpinner.fail();
console.log("err", chalk.red(err));
reject(err);
return;
}
// 下载完成后关闭loading,chalk改变提示文本颜色
downSpinner.succeed(chalk.green("模板下载成功!"));
console.log(`Done. Now run:\r\n`);
console.log(chalk.green(`cd ${name}`));
console.log(chalk.blue("npm install"));
console.log("npm run dev\r\n");
resolve();
});
});
};
设置远程仓库地址以及分支
const remoteList = {
1: "https://gitee.com/theGreatWallCCG/vue3-template-cli.git",
2: "https://github.com/BenjaminCCG/vue3-template-cli.git",
};
const branch = "main";
修改 getInputInfo 函数
const getInputInfo = async () => {
const res = await prompts(promptsOptions);
if (!res.name || !res.template) return;
gitClone(`direct:${remoteList[res.template]}#${branch}`, res.name, {
clone: true,
});
};
此时新建个目录,终端执行 cc-cli
大功告成!!!
发布 npm
接下来终端执行 npm login
输入自己的 npm 账号密码,没有的自行注册
然后执行 npm publish
进行发布
这样你的小伙伴就可以执行 npm i cc-cli-app -g
去使用你开发的脚手架啦
完整代码
#! /usr/bin/env node
import commandLineArgs from "command-line-args";
import commandLineUsage from "command-line-usage";
import chalk from "chalk";
import prompts from "prompts";
import ora from "ora";
import download from "download-git-repo";
import fs from "fs";
const argOptions = [
{ name: "help", alias: "h", type: Boolean },
{ name: "version", alias: "v", type: Boolean },
{ name: "init", type: Boolean },
];
const helpSections = [
{
header: "cc-cli",
content: "一个快速生成开发环境的脚手架",
},
{
header: "Options",
optionList: [
{
name: "version",
typeLabel: "{underline boolean}",
description: "版本号",
},
{
name: "init",
typeLabel: "{underline boolean}",
description: "初始化",
},
],
},
];
const options = commandLineArgs(argOptions);
if (options.help) {
console.log(commandLineUsage(helpSections));
}
const promptsOptions = [
{
type: "text", // 输入
name: "name",
message: "项目名称",
validate(val) {
if (!val) return "模板名称不能为空!";
if (fs.existsSync(val)) return "项目名已存在";
if (val.match(/[^A-Za-z0-9\u4e00-\u9fa5_-]/g))
return "模板名称包含非法字符,请重新输入";
return true;
},
},
{
type: "select", // 单选
name: "template",
message: "选择来源",
choices: [
{ title: "gitee", value: 1 },
{ title: "github", value: 2 },
],
},
];
const gitClone = (remote, name, option) => {
const downSpinner = ora("正在下载模板...").start();
return new Promise((resolve, reject) => {
download(remote, name, option, (err) => {
if (err) {
downSpinner.fail();
console.log("err", chalk.red(err));
reject(err);
return;
}
downSpinner.succeed(chalk.green("模板下载成功!"));
console.log(`Done. Now run:\r\n`);
console.log(chalk.green(`cd ${name}`));
console.log(chalk.blue("npm install"));
console.log("npm run dev\r\n");
resolve();
});
});
};
const remoteList = {
1: "https://gitee.com/theGreatWallCCG/vue3-template-cli.git",
2: "https://github.com/BenjaminCCG/vue3-template-cli.git",
};
const branch = "main";
const getInputInfo = async () => {
const res = await prompts(promptsOptions);
if (!res.name || !res.template) return;
gitClone(`direct:${remoteList[res.template]}#${branch}`, res.name, {
clone: true,
});
};
getInputInfo();