当前位置: 首页 > news >正文

自定义脚手架

例如我们要创建一个脚手架名字叫 my-cli, 安装命令 my-cli create <projectName>

  • 准备插件
    • commander 命令行参数解析器
    • inquirer 命令行交互模块
    • axios 网络请求
    • download-git-repo git模板下载插件自动解压
    • ora 命令行loading
    • chalk 命令行文字样式
  • package.json 配置
  "main": "lib/index.js","bin": {"my-cli": "bin/my-cli.js"},"type": "module", //es6 模块// bin 下面的配置会在客户端安装后创建符号连接 然后就可以使用my-cli 命令// main 下面是需要导出的模块
  • bin/my-cli.js
import {program} from 'commander'
program
.command('create <projectName>') //定义命令
.description('创建项目') //描述
.option('-f, --force', 'can overwrite target directory if it exists') //配置参数,这里为是否覆盖 值true/false
.action((projectName, options) => { import('../lib/create.js').then(module => {//../lib/create.js 为模板下载文件// options 为提供的参数例如 my-cli create newPro --force, 这里会获取到forcemodule.default(projectName, options) //执行})
})
program.parse(process.argv)
  • lib/create.js
import fs from "fs"; //node 文件模块
import path from "path"; 
import inquirer from "inquirer";
import Generate from "./generate.js"; //模板下载类
export default async function createTemplate(name, options) {const pwd = process.cwd(); //当前绝对路径const targetAir = path.join(pwd, name); //模板文件路径if (fs.existsSync(targetAir)) { //如果存在同名文件if (options.force) { //是否覆盖fs.rmSync(targetAir, { recursive: true, force: true }); //删除} else {const res = await inquirer.prompt([ //命令行交互 是否覆盖{type: "confirm",name: "cover",message: "Target directory already exists. Continue?",default: false,choices: [ //命令行选项{name: "Overwrite",value: true,},{name: "Cancel",value: false,},],},]);if (!res.cover) {return;}fs.rmSync(targetAir, { recursive: true, force: true });}}const generate = new Generate(name, targetAir);generate.create(); //开始创建
  • lib/generate
import ora from "ora"; 
import { getRepoList, getTagList } from "./http.js"; //获取模板名称以及版本号,这两个函数就是axios请求,可以根据自己的模板实现下
//示例// export const getRepoList = async () => { 
//     const { data } = await axios.get('xxx')
//     return data
// }import inquirer from "inquirer"; 
import downloadGitRepo from "download-git-repo";
import { promisify } from "util"; //node内置模块  回调函数转 Promise
import path from "path";
import chalk from "chalk"; //命令行文字颜色样式
//定义loading 函数
async function wrapLoading(fn, message, ...args) {message = message || "waiting download ...";const spinner = ora(message);spinner.start(); //开始loadingtry {let data = await fn(...args);spinner.succeed(); //结束loadingreturn data;} catch (error) {if(error.code === 'ENOENT' && error.syscall === 'link'){//这里为因为客户端windows原因download-git-repo创建符号链接错误,本地测试忽略return true}spinner.fail();throw error;}
}export default class Generate {constructor(name, targetAir) {this.name = name;this.targetAir = targetAir;this.downloadGitRepo = promisify(downloadGitRepo);}async create() {// 获取模板名称const repo = await this.getRepo(); //获取模板名称const tag = await this.getTag(repo); //获取版本号this.downTemplate(repo, tag); //下载模板}async getRepo() {const repos = await wrapLoading(getRepoList, "waiting download template list ... ");const repo = await inquirer.prompt([ //命令交互选择模板{type: "list",name: "repo",message: "please choose a template to create project",choices: repos.map(item => item.name),},]);return repo.repo;}async getTag(repo) { const tags = await wrapLoading(getTagList, "waiting download template tag list ... ", repo);const tag = tags[0]; //默认最新版本号return tag.name;}async downTemplate(repo, tag) {const templateLink = `xxx/${repo}#${tag}`; //这里注意下download-git-repo 插件会自动拼上 https://github.com/为头await wrapLoading(this.downloadGitRepo,"waiting download template ... ",templateLink,path.resolve(process.cwd(), this.name), //模板的绝对路径);console.log(`/r/nSuccessful download template ${chalk.cyan(this.name)}`); //下载模板成功提示}
}
http://www.dtcms.com/a/434840.html

相关文章:

  • 云空间布置网站seo顾问赚钱吗
  • 网络设备中的硬件转发和软件转发
  • 永州建设网站公司网站开发费的税率是多少
  • js时间格式转化器
  • 攻防世界-Web-Web_php_unserialize
  • Deep Learning|01 RBF Network
  • 指针步长:C/C++内存操控的核心法则
  • 服装网站建设分析wordpress模板如何用
  • wordpress后台菜单管理程序代码优化网站
  • Windows 常用短文件名(8.3 格式)介绍
  • 【stm32】【edgetx】解析链接脚本文件(ld)
  • 商务网站构建与维护网站建设所有权
  • C语言速成秘籍——跳转语句(goto)
  • WPF实现串口热插拔 (提供百度网盘源代码)
  • 企业网站关键词排名南京比较好的网络策划公司
  • FFmpeg 核心 API 系列:avcodec_find_decoder / avcodec_alloc_context3 / avcodec_open2
  • 文件上传简单的绕过总结
  • Visual Studio Code中launch.json深度解析:C++调试的艺术
  • 天长市建设局网站惠来做网站
  • 51单片机红外遥控
  • Java 集合 “List + Set”面试清单(含超通俗生活案例与深度理解)
  • 云南网站建设哪个好软文广告平台
  • 《嵌入式 – GD32开发实战指南(RISC-V版本)》第8章 PWM输出实现
  • HNU 编译系统 第一次作业
  • 网站怎么做交易平台图片生成网页链接在线
  • 渗透测试中的信息收集:文档元数据
  • minikube 的 kubernetes 入门教程-kubeSphere
  • 深圳 手机网站建设彩妆做推广的网站
  • 网站跳转是什么意思郑州建站网站的公司
  • 老题新解|再求 f(x,n)