发布一个脚手架,封装常用的项目架构。
今天开始搭建自己的脚手架了,这里开始记录一下踩坑的过程。这个系列将会分成几大部分进行更新,第一版本主要是基于脚手架基本的创建流程的介绍,一步一步创建属于自己的定制化的脚手架。下载所指向的仓库模板可以自己去定义。在第一个版本中没有实现高度定制化的功能。只能下载你在github私服里面写好的项目模板。第二个版本现在正在建设中,目标是实现高度定制化的脚手架,通过脚手架自定义生成你所选择的功能模块,比如typescript、babel、vuex、vue2、vue3、vite、axios、pinia等多项定制化功能自动进行项目框架的生成。第三个版本是在第二个版本中作进一步的丰富,将会加入我自己写好的指令库、UI组件库等功能。
先放项目npm地址: www.npmjs.com/package/dgt…
这是github脚手架的源码:github.com/DGT18229282…
这里先标明所用到的第三方库,chalk:终端文字颜色样式。path:路径模块。
fs-extra:文件模块。inquirer:用户交互模块。ora:输出动画模块。
项目最终的目录结构:
第一步:
初始化项目基本结构,生成基本package.json文件:
npm init -y
生成:
{
"name": "dgt-cli",
"version": "1.0.0",
"description": "我的第一个脚手架",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "DGT",
"license": "ISC",
// 这里配置入口文件,并挂载命令到全局
"bin": {
"dgtCli":"bin/enter.js"
}
}
在项目根目录下创建bin目录,在bin目录下面创建enter.js:
#! /usr/bin/env node
// 表明当前环境是在node环境下运行
console.log('helloWorld')
第一行是为了指定当前的环境是node环境,必须要添加,不添加会报错。完成这一步后修改package.json指定入口文件,注意一定要用对象的形式,不然会报错。 第二步:
因为与用户进行交互需要用到comannd库,这里先安装一下:
npm i commander
现在修改入口文件:Step2: version 方法可以配置版本信息提示 Step3: name 和 usage 方法分别配置 cli 名称和 --help 第一行提示
#! /usr/bin/env node
// 表明当前环境是在node环境下运行
const program = require("commander"); // commander 来实现脚手架命令的配置
program.name("dgt-cli").usage(`<command> [option]`).version(`1.0.0`);
program.parse(process.argv); // process.argv 是 nodejs 提供的属性
console.log("helloWorld");
当运行dgt-cli create ***的时候会从enter.js开始,
#! /usr/bin/env node
// 表明当前环境是在node环境下运行
const program = require("commander"); // commander 来实现脚手架命令的配置
const chalk = require("chalk"); // chalk用美化终端命令的样式
program.name("dgt-cli").usage(`<command> [option]`);
program.version(`dgt-cli ${require("../package.json").version}`);
program
.command("create <project-name>") // 增加创建指令
.description("use dgt-cli create ** to create a new program") // 添加描述信息
.option(
"-f, --force",
"overwrite target directory if it exists(如果目录存在,强制删除)"
) // 强制覆盖
.action((projectName, cmd) => {
// 处理用户输入create 指令附加的参数
require("../lib/create")(projectName, cmd);
});
program
.command("config [value]") // config 命令
.description("inspect and modify the config")
.option("-g, --get <key>", "get value by key")
.option("-s, --set <key> <value>", "set option[key] is value")
.option("-d, --delete <key>", "delete option by key")
.action((value, keys) => {
// value 可以取到 [value] 值,keys会获取到命令参数
console.log(value, keys);
});
// 监听 --help 指令
program.on("--help", function () {
// 前后两个空行调整格式,更舒适
console.log();
console.log(
` Run ${chalk.green(
"dgt-cli <command> --help"
)} for detailed usage of given command.`
);
console.log();
});
program.parse(process.argv); // process.argv 是 nodejs 提供的属性
可知这里注册了一个comannd指令,create。 现在进入到create方法里面看一看到底发生了什么?
/*
*@Description: 创建项目的方法
*@MethodAuthor: DGT
*@ param: {
programeName:项目名称,
cmd:用户口令对象
}
*@ Date: @Date:2022-05-31 20:06:35
*/
const path = require("path"); // 路径模块
const fs = require("fs-extra"); // 文件读取操作
const chalk = require("chalk"); // 输出美化
const download = require("../utils/download"); //下载仓库代码
const oraClass = require("../utils/oraClass"); // 封装ora动画
const isOverwriteFun = require("../interactives/isOverWrite"); // 获取是否覆盖同名文件交互
const selectVueTypeFun = require("../interactives/selectVueType"); // 获取选择下载的对应的vue2还是vue3的模板仓库
const loadObj = new oraClass();
module.exports = async function (projectName, options) {
// 获取当前工作目录
const cwd = process.cwd();
// 拼接得到项目目录
const targetDirectory = path.join(cwd, projectName);
// 判断目录是否存在
if (fs.existsSync(targetDirectory)) {
// 判断是否使用 --force 参数
if (options.force) {
// 删除重名目录(remove是个异步方法)
await fs.remove(targetDirectory);
} else {
let isOverwrite = await isOverwriteFun();
// 选择 Cancel
if (!isOverwrite) {
console.log("Cancel");
return;
} else {
// 选择 Overwirte ,先删除掉原有重名目录
loadObj.start("removing origin file...");
await fs.remove(targetDirectory);
loadObj.sucess("removing origin file success!");
}
}
}
let vue_version = await selectVueTypeFun(); // 获取对应的仓库模板
download(`${returnRightUrl(vue_version)}`, projectName,tips);
};
/*
*@Description: 根据用户输入返回对应的项目模板地址
*@MethodAuthor: DGT
*@ param: {type:vue版本}
*@ Date: @Date:2022-06-01 15:24:46
*/
const returnRightUrl = (type) => {
const urlMap = new Map();
urlMap
.set("v2", "github:DGT18229282792/npm-auto-loader")
.set("v3", "github:DGT18229282792/monitor-sdk");
return urlMap.get(type);
}
/*
*@Description: 下载成功提示开启项目
*@MethodAuthor: DGT
*@ param: {}
*@ Date: @Date:2022-06-02 23:22:27
*/
const tips = (projectName) =>{
console.log(``)
console.log(`${chalk.green(`cd ${projectName}`)}`)
console.log(`${chalk.green(`npm install`)}`)
console.log(`${chalk.green(`npm run serve`)}`)
console.log(``)
}
首先获取当前的工作目录,然后拼接得到项目的目录。然后判断有没有同名的文件夹存在。如果有的话就调用是否覆盖删除同名文件夹方法。然后弹出vue模板选择交互。获取到用户所选择的你事先写好的vue版本。最后调用我们的下载方法进行下载git仓库的项目到我们对应的文件夹中。到这里create指令就结束了。 我们就能够指定git仓库,然后让用户自己选择然后进行下载模板。
最后一步是发布到npm。
终端登录你的npm账号。执行npm login按照提示进行输入。登录成功后。进行版本的配置。输入npm version 1.0.0指定你的脚手架的第一个版本号。然后执行npm publish进行发布。最后你再登录npm官网,在你的主页就可以看到你刚刚上传的这个脚手架了。
其他人使用起来也特别简单。只需要安装npm i dgt-cli就可以了。