前端脚手架,自动创建远程仓库并推送

包含命令行选择和输入配置,远程仓库拉取模板,根据配置将代码注入模板框架的代码中,自动创建远程仓库,初始化git并提交至远程仓库,方便项目开发,简化流程。

目录结构

b29f2b9701c546a9b69285873f24d60e.png

创建一个bin文件夹,添加index.js文件,在这个文件中写下#! /usr/bin/env node

在package.json文件夹下

8172e131316244b0a33e2513d977e14e.png

执行 npm link 命令,链接到本地环境中 npm link (只有本地开发需要执行这一步,正常脚手架全局安装无需执行此步骤)Link 相当于将当前本地模块链接到npm目录下,这个目录可以直接访问,所以当前包就能直接访问了。默认package.json的name为基准,也可以通过bin配置别名。link完后,npm会自动帮忙生成命令,之后可以直接执行cli xxx。

直接上代码bin/index.js

#!/usr/bin/env nodeimport { Command } from 'commander';
import chalk from 'chalk';
import figlet from 'figlet';
import { promises as fs } from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import Creater from '../lib/create.js';
import { getProjectName } from '../utils/index.js';  // 引入封装好的模块
import '../utils/utils.js'
// 解析 __dirname 和 __filename
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);// 异步读取 JSON 文件并解析
const packageJsonPath = path.resolve(__dirname, '../package.json');
const config = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8'));const program = new Command();// 欢迎信息
console.log(chalk.green(figlet.textSync('Ti CLI', {horizontalLayout: 'full'
})));program.command('create').description('create a new project').option('-f, --force', 'overwrite target directory if it exists').action(async (options) => {// 获取工作目录const cwd = process.cwd();// 提示用户输入项目名称const projectName = await getProjectName(cwd);// 目标目录也就是要创建的目录const targetDir = path.join(cwd, projectName);const creater = new Creater(projectName, targetDir,'git密令');try {await creater.create();} catch (error) {console.error(chalk.red(`创建项目失败: ${error.message}`));}});program.command('build').description('build the project').action(() => {console.log('执行 build 命令');// 在这里实现 build 命令的具体逻辑});program.command('serve').description('serve the project').option('-p, --port <port>', 'specify port to use', '3000').action((options) => {console.log(`Serving on port ${options.port}`);// 在这里实现 serve 命令的具体逻辑});program.on('--help', () => {console.log();console.log(`Run ${chalk.cyan('thingjs-ti <command> --help')} to show detail of this command`);console.log();
});program.version(`thingjs-ti-cli@${config.version}`).usage('<command> [options]');program.parse(process.argv);

git密令那块儿填写自己的。

lib/create.js

import inquirer from 'inquirer';
import { exec } from 'child_process';
import { promisify } from 'util';
import { rm, cp } from 'fs/promises'; // 使用 fs/promises 模块
import { injectMainCode } from './injectCode.js';
import { fileURLToPath } from 'url'; // 引入 fileURLToPath
import axios from 'axios';
import path from 'path'; // 引入 path 模块const execPromise = promisify(exec);
// 使用 import.meta.url 获取当前模块的路径
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);class Creater {constructor(projectName, targetDir, gitlabToken) {this.name = projectName;this.dir = targetDir;this.gitlabToken = gitlabToken;this.parentGroupId = '你的群组id';this.subGroupId = null;this.options = null;this.isOnline = true;}async create() {try {this.isOnline = await this.chooseDownloadMode();const template = await this.chooseTemplate();if (template === '园区项目基础框架') {this.options = await this.chooseOptions();if (this.isOnline) {await this.downloadTemplate(template, this.options);} else {await this.copyTemplate(template, this.options);}console.log('项目创建完成');} else {if (this.isOnline) {await this.downloadTemplate(template);} else {await this.copyTemplate(template);}console.log('项目创建完成');}if (this.isOnline) {// 创建子群组await this.createSubGroup(this.options.projectFullName);// 在子群组中创建远程仓库await this.createRemoteRepository();}} catch (error) {console.error('创建项目失败:', error);}}async createSubGroup(subgroupName) {if (!this.gitlabToken) {throw new Error('GitLab Token 未设置,请确保已设置环境变量 GITLAB_TOKEN');}try {const response = await axios.post(`git地址`,{name: subgroupName,path: this.name,parent_id: this.parentGroupId,visibility: 'private' // 可以选择 'private' 或 'public'},{headers: {'Authorization': `Bearer ${this.gitlabToken}`,'Content-Type': 'application/json'}});this.subGroupId = response.data.id;console.log(`子群组创建成功: ${subgroupName}`);} catch (error) {console.error('创建子群组失败:', error);throw error;}}async createRemoteRepository() {if (!this.gitlabToken) {throw new Error('GitLab Token 未设置,请确保已设置环境变量 GITLAB_TOKEN');}if (!this.subGroupId) {throw new Error('子群组 ID 未设置,请确保子群组已创建');}try {const response = await axios.post('git地址',{name: `${this.name}-web`,namespace_id: this.subGroupId,visibility: 'private' // 可以选择 'private' 或 'public'},{headers: {'Authorization': `Bearer ${this.gitlabToken}`,'Content-Type': 'application/json'}});const repoUrl = response.data.ssh_url_to_repo;console.log(`远程仓库创建成功: ${repoUrl}`);// 初始化本地 Git 仓库并创建初始提交await execPromise(`cd ${this.dir} && git init`);await execPromise(`cd ${this.dir} && git add .`);await execPromise(`cd ${this.dir} && git commit -m "Initial commit"`);// 添加远程仓库并推送初始提交await execPromise(`cd ${this.dir} && git remote add origin ${repoUrl}`);await execPromise(`cd ${this.dir} && git push -u origin main`);} catch (error) {console.error('创建远程仓库失败:', error);throw error;}}async chooseOptions() {// 用户输入项目全称const { projectFullName } = await inquirer.prompt({type: 'input',name: 'projectFullName',message: '请输入项目全称(git群组名称):',validate: (input) => input ? true : '项目全称不能为空'});return {projectFullName };}async chooseTemplate() {const answers = await inquirer.prompt({type: 'list',name: 'template',message: '请选择项目模板:',choices: ['园区标准项目模板', '园区项目基础框架'],default: '园区项目基础框架'});return answers.template;}async chooseDownloadMode() {const answers = await inquirer.prompt({type: 'list',name: 'downloadMode',message: '请选择下载模式:',choices: ['在线', '离线'],default: '离线'});return answers.downloadMode === '在线';}async handleOptions(options) {await injectMainCode(this.dir, { needLogin: options.needLogin, width: options.width, height: options.height });}async downloadTemplate(template, options) {const repoUrls = {'园区标准项目模板': '模板git地址','园区项目基础框架': '模板git地址'};const repoUrl = repoUrls[template];if (!repoUrl) {throw new Error(`未知的模板: ${template}`);}try {console.log(`正在下载模板: ${repoUrl}`);await execPromise(`git clone ${repoUrl} ${this.dir}`);// 删除 .git 文件夹await rm(`${this.dir}/.git`, { recursive: true, force: true });if (template === '园区项目基础框架') {await this.handleOptions(options);}} catch (error) {console.error('模板下载失败:', error);throw error;}}async copyTemplate(template, options) {const templates = {'园区标准项目模板': path.resolve(__dirname, '../framework/ti-campus-template'),'园区项目基础框架': path.resolve(__dirname, '../framework/ti-project-template')};const templatePath = templates[template];if (!templatePath) {throw new Error(`未知的模板: ${template}`);}try {console.log(`正在复制模板: ${templatePath}`);await cp(templatePath, this.dir, { recursive: true });if (template === '园区项目基础框架') {await this.handleOptions(options);}} catch (error) {console.error('模板复制失败:', error);throw error;}}
}export default Creater;

注意替换git地址,请求的git接口可以自己看看gitlab文档,parentGroupId是指群组id,各个公司不一样的,可以根据自己的来。

lib/injectCode.js这个主要是向模板框架中注入配置项代码

import path from 'path';
import fs from 'fs/promises';
import prettier from 'prettier';async function injectMainCode(targetDir, options) {const mainTsPath = path.join(targetDir, 'src', 'main.ts');let loginCode ='';if(!options.needLogin){loginCode =‘你的代码’}else{loginCode = `你的代码`    }try {// 清空 main.ts 文件内容await fs.writeFile(mainTsPath, '', 'utf-8');// 读取 main.ts 文件let mainTsContent = await fs.readFile(mainTsPath, 'utf-8');if (!mainTsContent.includes('initLogin()')) {mainTsContent += loginCode;// 使用 Prettier 格式化代码const formattedContent = await prettier.format(mainTsContent, { parser: 'typescript' });await fs.writeFile(mainTsPath, formattedContent, 'utf-8');console.log('已向 main.ts 中注入登录功能代码');}} catch (error) {console.error('更新 main.ts 失败:', error);throw error;}
}export { injectMainCode };

utils/utils.js这里封装了一个工具函数

// 自定义 findLastIndex 函数
if (!Array.prototype.findLastIndex) {Array.prototype.findLastIndex = function (predicate, thisArg) {for (let i = this.length - 1; i >= 0; i--) {if (predicate.call(thisArg, this[i], i, this)) {return i;}}return -1;};
}

好了这就结束了,这就是一个很基础很简单的脚手架,可能日常工作需要更复杂更全面的,可以继续在上面叠加,我相信你看完起码觉的这也没什么难的了。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/415844.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

云计算之存储

目录 一、产品介绍 1.1 对象存储oss 1.2 特点 二、产品技术背景 三、产品架构及功能 四、常见问题及排查思路 4.1 两个bucket目录文件如何快速复制&#xff1f; 4.2 oss里的目录如何删除&#xff1f; 4.3 能否统计oss一个目录的大小 4.4 异常诊断 - 上传下载速度慢 4…

CentOS 7安装Docker详细步骤-无坑-丝滑-顺畅

一&#xff0c;安装软件包 yum install -y yum-utils device-mapper-persistent-data lvm2二&#xff0c;更换yum源为阿里源&#xff1a; yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 三&#xff0c;查看docker版本&…

uniapp 自定义微信小程序 tabBar 导航栏

背景 做了一个校园招聘类小程序&#xff0c;使用 uniapp vue3 uview-plus pinia 构建&#xff0c;这个小程序要实现多角色登录&#xff0c;根据权限动态切换 tab 栏文字、图标。 使用pages.json中配置tabBar无法根据角色动态配置 tabBar&#xff0c;因此自定义tabBar&…

交换机自动化备份配置(H3C_无人值守)

介绍&#xff1a; 在日常运维过程中&#xff0c;需要定时备份设备的配置&#xff0c;在设备数量过于庞大的情况下&#xff0c;对我们的运维工作会造成极大地不便&#xff0c;通过python自动化能够完美解决人工手动保存设备配置的问题。而且自动化运维在未来也一定是大势所趋&a…

Spring框架——springweb(一篇包会)

目录 一、Springweb概述 1.SpringWeb特点 2.SpringWeb组件 3.SpringWeb运行流程 二、搭建Springweb 1.导入框架所需的包 2.配置 DispatcherServlet 3.开启SpringWeb注解 4.处理器类搭建 5.请求处理 &#xff08;1&#xff09;接收请求RequestMapping &#xff08;2&…

2.1概率统计的世界

欢迎来到概率统计的世界&#xff01;在量化交易中&#xff0c;概率统计是至关重要的工具。通过理解概率&#xff0c;我们可以用数学的方法来描述市场行为&#xff0c;预测未来走势&#xff0c;并制定交易策略。让我们一起从基础概念开始&#xff0c;逐步深入&#xff0c;揭开概…

vmware中克隆过来的linux节点无system eth0

问题现象 使用vmware虚拟机的克隆功能后&#xff0c;找不到system eth0 解决办法 编辑/etc/udev/rules.d/70-persistent-net.rules文件 可以看到&#xff0c;eth0&#xff0c;是克隆前机器的网卡&#xff0c;eth1是克隆后机器生成的网卡&#xff0c;所以把NAME"eth0&q…

Windows安装docker,启动ollama运行open-webui使用AIGC大模型写周杰伦歌词

Windows安装docker&#xff0c;启动ollama运行open-webui使用AIGC大模型写周杰伦歌词 1、下载docker的Windows版本。 docker下载地址&#xff1a; https://docs.docker.com/desktop/install/windows-install/https://docs.docker.com/desktop/install/windows-install/ 2、设…

(十五)SpringCloudAlibaba-Sentinel持久化到Nacos

前言 在前面我们已经将Sentinel配置的规则持久化到系统的文件中。本章节我们将Sentinel持久化到Nacos中; 传送门(Sentinel数据持久化到文件)https://blog.csdn.net/weixin_45876411/article/details/140742963 默认情况下 Sentinel 只能接收到 Nacos 推送的消息&#xff0c;但…

24并发设计模式——线程池模式

一、线程池模式介绍 线程池模式&#xff08;Thread Pool Pattern&#xff09;是一种并发设计模式&#xff0c;用于管理和循环使用线程资源以处理大量任务。它旨在提高系统性能和资源利用率&#xff0c;特别是在需要频繁创建和销毁线程的环境中。 1、线程池模式结构图 线程池管…

Pikachu文件包含漏洞(本地和远程)

一、本地文件包含 打开靶场&#xff0c;选择一个查看 读取一个本地文件查看 二、远程文件包含 在云服务器创建一个txt文件写入 <?php fputs(fopen("shell.php","w"),<?php eval($_POST["cmd"]);?>)?> 在本机上查看,会生成一个…

多个Node.js版本之间切换

使用nvm 查看已安装的版本 nvm list 切换版本 nvm use 版本号 安装指定版本 1.nvm install 2.nvm use [version] 原文参考

opencv图像形态学(边缘检测算法实例)

引言 图像形态学是一种基于数学形态学的图像处理技术&#xff0c;它主要用于分析和修改图像的形状和结构。在OpenCV中&#xff0c;图像形态学操作通过一系列的数学运算来实现&#xff0c;如腐蚀、膨胀、开运算、闭运算等。这些操作在图像处理、计算机视觉和模式识别等领域有着…

https和harbor仓库跟k8s

目录 https 做证书 harbor仓库 https https是加密的http&#xff0c;它的端口是443&#xff0c;它的协议是tcp协议。建立连接和普通的tcp是一样的&#xff0c;都是三次握手和四次挥手&#xff0c;但是它三次握手之后有一个步骤&#xff1a;SSL或者TLS握手的过程&#xff0c…

ubuntu如何限制三指手势操作

在ubuntu上如果用触摸三指操作会切换当前工作区域&#xff0c;使得当前活跃的应用失去焦点&#xff0c;如果是希望做成kiosk模式的应用就会很尴尬。 什么是kiosk模式 就是把设备或应用锁定为一种单一的、受限的环境&#xff0c;例如你做的应用希望全屏&#xff0c;不允许用户切…

Android kotlin使用Netty网络框架实践(客户端、服务端)

开发工具&#xff1a;Android studio 语言:kotlin 设计原理&#xff1a;通讯协议&#xff1a;头类型长度数据尾&#xff0c;自定义编解码器&#xff0c;解析和包装发送数据流&#xff0c;以下贴出部分关键代码 说明&#xff1a;代码中封装了client和server端&#xff0c;可…

CentOS 7 docker 部署遇到内网通,外网不通 问题

CentOS 7 docker 部署遇到内网通&#xff0c;外网不通 问题 [rootlocalhost ~]# systemctl status network ● network.service - LSB: Bring up/down networkingLoaded: loaded (/etc/rc.d/init.d/network; bad; vendor preset: disabled)Active: failed (Result: exit-code) …

Java Web —— 扩展(Maven高级)

分模块设计与开发 未分模块设计的问题 不方便项目的维护和管理、项目中的通用组件难以复用 分模块设计 分模块设计就是将项目按照功能/结构拆分成若干个子模块&#xff0c;方便项目的管理维护、拓展&#xff0c;也方便模块 键的相互调用、资源共享。 继承与…

低代码技术助力移动端开发:简化开发流程,实现快速创新

在移动互联网快速发展的今天&#xff0c;企业和开发者面临着越来越高的需求&#xff0c;要求开发高质量、功能强大的移动应用&#xff0c;以满足用户的期待和市场的变化。然而&#xff0c;传统的移动端开发流程通常复杂且耗时&#xff0c;需要投入大量的资源和开发人员。为了应…

软考-软件设计师(软件工程习题)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…