在使用插件和vite等框架的时候,我们只要npm i xxx就可以了。在平时的工作中,由于公司业务线的原因,偏向toB系统会比较多。一旦涉及到从零到一的项目,其实每个项目的框架都差异不大,所以能不能先把类似的框架保存起来,要用的时候直接下载就行了,而不是每次都得重新去搭建一个,各种类似的工具,反复npm。
方法一:
将类似的框架架构搭建好,上传到自己的git仓库,要用的时候直接clone就行。
方法二:
我也想模仿一下vite创建对应框架的方法,直接npm i xxx就行了。这样做的好处就是,只要你记得命令,就可以快速下载自己想要的模版。
具体实现步骤:
1.将所有项目模版都放在一个公共库当中,
2.编写cli代码,实现下载对应模版的步骤,并实现跟操作者简单的交互。
3.将cli脚本发布到npm官网上
3.直接本地npm i xxx既可以获取模版
1.准备模版
1.我个人用的github账号,然后自己名下有对应的框架模版,目前自己创建了一个简单的vite+ts+element plus+eslint+prettier+husky的常规框架模版。(可根据自己的需求,使用gitee等库,但请注意:每个git库动态获取模版信息的地址拼接规则不同)
2.编写脚本
npm init -y 初始化
创建bin文件夹
bin/cli.js文件内容
#! /usr/bin/env node
const program = require("commander"); //cli命令工具
const package = require("../package.json");
const inquirer = require("inquirer"); //可以获取用户输入内容的交互工具
// const templates = require("./templates.js");//固定模版数据
const { getGitReposList } = require("./api.js"); // 动态获取git库的模版内容
const downloadGitRepo = require("download-git-repo"); //下载git模版的操作
const path = require("path");
const ora = require("ora"); // 引入ora-实现执行中的loading效果
const loading = ora("正在下载模版...");
const fs = require("fs-extra"); // 引入fs-extra
// 定义当前版本
program.version(`v${package.version}`);
//新建脚本的交互
program
.command("create [projectName]") // [projectName]是可选 <projectName>是必填
.option("-t, --template <template>", "模版名称") // 配置项 --template xxx
.description("创建模版")
.action(async (projectName, options) => {
// //创建项目姓名
// const { name } = await inquirer.prompt({
// type: "input",
// name: "name",
// message: "请输入项目名称:",
// });
// console.log("项目名称:", name);
// // 新增选择模版代码
// const { template } = await inquirer.prompt({
// type: "list",
// name: "template",
// message: "请选择模版:",
// choices: templates, // 模版列表
// });
// console.log("模版:", template);
// 添加获取模版列表接口和loading
const getRepoLoading = ora("获取模版列表...");
getRepoLoading.start();
const templates = await getGitReposList("wanwenxing");
getRepoLoading.succeed("获取模版列表成功!");
// 1. 从模版列表中找到对应的模版
let project = templates.find(
(template) => template.name === options.template
);
// 2. 如果匹配到模版就赋值,没有匹配到就是undefined
let projectTemplate = project ? project.value : undefined;
console.log("命令行参数:", projectName, projectTemplate);
// 3. // 如果用户没有传入名称就交互式输入
if (!projectName) {
const { name } = await inquirer.prompt({
type: "input",
name: "name",
message: "请输入项目名称:",
});
projectName = name; // 赋值输入的项目名称
}
console.log("项目名称:", projectName);
// 4. 如果用户没有传入模版就交互式输入
if (!projectTemplate) {
const { template } = await inquirer.prompt({
type: "list",
name: "template",
message: "请选择模版:",
choices: templates, // 模版列表
});
projectTemplate = template; // 赋值选择的项目名称
}
console.log("模版:", projectTemplate);
// 目标文件夹 = 用户命令行所在目录 + 项目名称
const dest = path.join(process.cwd(), projectName);
// 判断文件夹是否存在,存在就交互询问用户是否覆盖
if (fs.existsSync(dest)) {
const { force } = await inquirer.prompt({
type: "confirm",
name: "force",
message: "目录已存在,是否覆盖?",
});
// 如果覆盖就删除文件夹继续往下执行,否的话就退出进程
force ? fs.removeSync(dest) : process.exit(1);
}
loading.start();
//下载git模版
downloadGitRepo(projectTemplate, dest, function (err) {
if (err) {
loading.fail("创建模版失败:" + err.message); // 失败loading
} else {
loading.succeed("创建模版成功!"); // 成功loadings
// 添加引导信息(每个模版可能都不一样,要按照模版具体情况来)
console.log(`\ncd ${projectName}`);
console.log("npm i");
console.log("npm start\n");
}
});
});
// 解析用户执行命令传入参数
program.parse(process.argv);
program.on("--help", () => {}); // 添加--help
bin/api.js内容
const https = require("https");
/** 获取用户git仓库列表信息 */
function getGitReposList(username) {
return new Promise((resolve, reject) => {
https
.request(
`https://api.github.com/users/${username}/repos`, //github官网提供的对应Api:https://api.github.com/
{
headers: {
"User-Agent": username,
},
},
(res) => {
let data = "";
res.on("data", (chunk) => {
data += chunk.toString();
});
res.on("end", () => {
const list = JSON.parse(data);
// console.log("git返回的用户名下的模版信息》〉》〉",list)
resolve(
list.map((item) => ({
// 组合成模版所需要的name,value结构
name: item.name,
value: `https://github.com:${username}/${item.name}`,//注意,每个git仓库的拼接规则可能有差异
}))
);
});
res.on("error", (err) => {
reject(err);
});
}
)
.end();
});
}
module.exports = {
getGitReposList,
};
如果不想动态获取远程的框架模版,可以直接写死。
缺点:
1.如果远程仓库中新增或者删除模版,则需要去同步更新cli脚手架代码
bin/template.js内容
/** 暴露模版代码
* 方法1:存在脚手架目录下
* 方法2:存储在远程git上,每次都从远程拉取代码
*/
module.exports = [
{
name: 'webpack5-react-ts',
value: 'https://github.com:guojiongwei/webpack5-react-ts'
},
{
name: 'react18-vite2-ts',
value: 'https://github.com:guojiongwei/react18-vite2-ts'
},
{
name: 'dumi2-demo',
value: 'https://github.com:guojiongwei/dumi2-demo'
}
]
3.发布到npm
npm login指令,获取登录链接,登录后执行npm publish命令(注意:后期若修改cli脚本,重新发布需要去更改对应的version或者是cli的名称)