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

2024-09-04 04:04

本文主要是介绍前端脚手架,自动创建远程仓库并推送,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

包含命令行选择和输入配置,远程仓库拉取模板,根据配置将代码注入模板框架的代码中,自动创建远程仓库,初始化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.chinasem.cn/article/1134940

相关文章

部署Vue项目到服务器后404错误的原因及解决方案

《部署Vue项目到服务器后404错误的原因及解决方案》文章介绍了Vue项目部署步骤以及404错误的解决方案,部署步骤包括构建项目、上传文件、配置Web服务器、重启Nginx和访问域名,404错误通常是... 目录一、vue项目部署步骤二、404错误原因及解决方案错误场景原因分析解决方案一、Vue项目部署步骤

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

前端原生js实现拖拽排课效果实例

《前端原生js实现拖拽排课效果实例》:本文主要介绍如何实现一个简单的课程表拖拽功能,通过HTML、CSS和JavaScript的配合,我们实现了课程项的拖拽、放置和显示功能,文中通过实例代码介绍的... 目录1. 效果展示2. 效果分析2.1 关键点2.2 实现方法3. 代码实现3.1 html部分3.2

Python创建Excel的4种方式小结

《Python创建Excel的4种方式小结》这篇文章主要为大家详细介绍了Python中创建Excel的4种常见方式,文中的示例代码简洁易懂,具有一定的参考价值,感兴趣的小伙伴可以学习一下... 目录库的安装代码1——pandas代码2——openpyxl代码3——xlsxwriterwww.cppcns.c

CSS弹性布局常用设置方式

《CSS弹性布局常用设置方式》文章总结了CSS布局与样式的常用属性和技巧,包括视口单位、弹性盒子布局、浮动元素、背景和边框样式、文本和阴影效果、溢出隐藏、定位以及背景渐变等,通过这些技巧,可以实现复杂... 一、单位元素vm 1vm 为视口的1%vh 视口高的1%vmin 参照长边vmax 参照长边re

CSS3中使用flex和grid实现等高元素布局的示例代码

《CSS3中使用flex和grid实现等高元素布局的示例代码》:本文主要介绍了使用CSS3中的Flexbox和Grid布局实现等高元素布局的方法,通过简单的两列实现、每行放置3列以及全部代码的展示,展示了这两种布局方式的实现细节和效果,详细内容请阅读本文,希望能对你有所帮助... 过往的实现方法是使用浮动加

Go Mongox轻松实现MongoDB的时间字段自动填充

《GoMongox轻松实现MongoDB的时间字段自动填充》这篇文章主要为大家详细介绍了Go语言如何使用mongox库,在插入和更新数据时自动填充时间字段,从而提升开发效率并减少重复代码,需要的可以... 目录前言时间字段填充规则Mongox 的安装使用 Mongox 进行插入操作使用 Mongox 进行更

css渐变色背景|<gradient示例详解

《css渐变色背景|<gradient示例详解》CSS渐变是一种从一种颜色平滑过渡到另一种颜色的效果,可以作为元素的背景,它包括线性渐变、径向渐变和锥形渐变,本文介绍css渐变色背景|<gradien... 使用渐变色作为背景可以直接将渐China编程变色用作元素的背景,可以看做是一种特殊的背景图片。(是作为背

C语言中自动与强制转换全解析

《C语言中自动与强制转换全解析》在编写C程序时,类型转换是确保数据正确性和一致性的关键环节,无论是隐式转换还是显式转换,都各有特点和应用场景,本文将详细探讨C语言中的类型转换机制,帮助您更好地理解并在... 目录类型转换的重要性自动类型转换(隐式转换)强制类型转换(显式转换)常见错误与注意事项总结与建议类型

使用Python在Excel中创建和取消数据分组

《使用Python在Excel中创建和取消数据分组》Excel中的分组是一种通过添加层级结构将相邻行或列组织在一起的功能,当分组完成后,用户可以通过折叠或展开数据组来简化数据视图,这篇博客将介绍如何使... 目录引言使用工具python在Excel中创建行和列分组Python在Excel中创建嵌套分组Pyt