前端项目构建打包生成Git信息文件

请添加图片描述

系列文章目录

TypeScript 从入门到进阶专栏


文章目录

  • 系列文章目录
  • 前言
  • 一、前端项目构建打包生成Git信息文件作用
  • 二、步骤
    • 1.引入相关的npm包
      • 1.1. **fs** 包
      • 1.2. **child_process** 包
      • 1.3. **os** 包 (非必须 如果你想生成的文件信息中包含当前电脑信息则可用)
      • 1.4. **path** 包 (非必须 如果你想生成的文件信息中包含当前项目版本信息则可用)
    • 2.创建脚本文件
    • 2.设置项目打包脚本
    • 3.运行项目打包命令
  • 我的脚本文件


前言

前端项目构建打包生成Git信息文件的作用是将当前代码所属的Git仓库的相关信息(例如commit hash、branch name、commit message等)保存在项目中的一个文件中。这样做的目的是为了方便在程序中获取和展示当前代码的版本信息,以及方便对项目进行版本管理和追踪。

一、前端项目构建打包生成Git信息文件作用

  1. 便于查看当前代码所属的Git分支和最近的commit hash,方便开发人员进行调试和追踪问题。
  2. 方便在应用程序界面或其他需要展示版本信息的地方展示当前代码的版本号,以便用户了解当前使用的是哪个版本的代码。
  3. 在持续集成和部署流程中,可以将生成的Git信息文件上传到服务器,方便在服务器端查看和追踪部署到服务器的代码版本。
  4. 可以结合自动化工具或脚本,在每次构建打包过程中自动更新Git信息文件,以保证该文件中的版本信息与当前代码一致,方便后续的版本管理和追踪。
  5. 方便开发人员在使用第三方工具或库时,能够快速确定所使用的版本,以解决可能出现的兼容性或功能问题。

二、步骤

1.引入相关的npm包

首先我们需要在项目中安装四个需要的npm包

1.1. fs

作用:提供了文件系统相关的功能,允许你在Node.js环境中对文件进行读取、写入、修改、删除等操作。。 用于生成最后的信息文件

安装方式如下

npm install fs --save-dev
或
pnpm add --save-dev
或
yran install fs --save-dev

1.2. child_process

是一个用于创建子进程的模块。它提供了一些方法来执行外部命令、创建子进程,并与其进行通信。

安装方式如下

npm install child_process --save-dev
或
pnpm child_process --save-dev
或
yran install child_process --save-dev

1.3. os 包 (非必须 如果你想生成的文件信息中包含当前电脑信息则可用)

os包可以让开发者在Node.js环境中访问操作系统相关的功能。

安装方式如下

npm install os --save-dev
或
pnpm os --save-dev
或
yran install os --save-dev

os包的方法

  1. os.platform():获取当前操作系统的平台名称,例如’win32’、'linux’等。
  2. os.arch():获取当前操作系统的CPU架构,例如’x64’、'arm’等。
  3. os.hostname():获取当前计算机的主机名。
  4. os.type():获取当前操作系统的类型,例如’Windows_NT’、'Linux’等。
  5. os.release():获取当前操作系统的版本号。
  6. os.totalmem():获取当前系统的总内存大小。
  7. os.freemem():获取当前系统的可用内存大小。
  8. os.cpus():获取当前计算机的CPU信息。
  9. os.networkInterfaces():获取当前计算机的网络接口信息。

1.4. path 包 (非必须 如果你想生成的文件信息中包含当前项目版本信息则可用)

npm install path --save-dev
或
pnpm path --save-dev
或
yran install path --save-dev

2.创建脚本文件

在项目的根目录文件下创建 automated_scripts 文件夹 在此文件夹下创建 build.js 文件 如下图所示。也可以放在别的位置 根据自己的项目来 。

请添加图片描述

build.js 文件 整体代码如下:

import fs from 'fs'; // 引入文件系统
import { execSync } from 'child_process'; // 开启一个子进程
import path from 'path';
import os from 'os';

// 获取当前命令行上下文路径
const currentDirectory = process.cwd();

// 日期格式转换函数  格式: 2024-1-10 16:57:40
const transferTime = (date) => {
	const currentDate = date ? new Date(date) : new Date();
	const year = currentDate.getFullYear();
	const month = currentDate.getMonth() + 1; // getMonth() 返回的是 0-11,需要加 1
	const dates = currentDate.getDate();
	const hours = currentDate.getHours();
	const minutes = currentDate.getMinutes();
	const seconds = currentDate.getSeconds();
	return `${hours}:${minutes}:${seconds} ${year}-${month}-${dates}`;
};

//主体函数
async function start() {
	console.log('\x1B[32m', '开始打包项目', '\x1B[0m');
	
	// 执行npm打包命令 这里根据 你自己项目打包时运行的命令进行修改 一般是vite build 
		execSync('vite build --mode production', {
			stdio: 'inherit',
		});
	// 获取当前git分支名称
		const branchName = execSync('git rev-parse --abbrev-ref HEAD')
			.toString()
			.trim();	
		//打包时间
		const date = new Date().toLocaleString();

		// 打印
		console.log(
			'\x1B[33m',
			'------------------------------------------',
			'\x1B[0m'
		);
		console.log(
			'\x1B[32m',
			'\t项目信息:\n' +
				`\t版本号:${currentVersion}\n` +
				`\t打包时间:${date}\n` +
				`\tgit分支名称:${branchName}\n`,
			'\x1B[0m'
		);
		console.log(
			'\x1B[33m',
			'------------------------------------------',
			'\x1B[0m'
		);
		
		const branch = execSync('git rev-parse --abbrev-ref HEAD')
			.toString()
			.trim();
		
		//此处添加git命令
		const gitDataMap ={
			'git.branch': 'git rev-parse --abbrev-ref HEAD',
			'git.commit.id': `git rev-parse --verify ${
				branch ? 'origin/' + branch : 'HEAD'
			}`,
			'git.commit.id.abbrev': `git rev-parse --short ${
				branch ? 'origin/' + branch : 'HEAD'
			}`,
			'git.commit.message.full': `git log -1 ${
				branch ? 'origin/' + branch : ''
			} --format="%B"`,
			'git.commit.message.short': `git log -1 ${
				branch ? 'origin/' + branch : ''
			} --format="%s"`,
			'git.commit.time': `git log -1 ${
				branch ? 'origin/' + branch : ''
			} --format="%cd"`,
			'git.commit.user.email': `git log -1 ${
				branch ? 'origin/' + branch : ''
			} --format="%ae"`,
			'git.commit.user.name': `git log -1 ${
				branch ? 'origin/' + branch : ''
			} --format="%an"`,
			'git.dirty': 'git status --porcelain',
			'git.remote.origin.url': 'git remote get-url origin',
			'git.total.commit.count': 'git rev-list --count HEAD',
		}

		Object.keys(gitDataMap).forEach((value) => {
			newStr[value] = execSync(gitDataMap[value]).toString().trim();
		});

		//将日志写入dist文件夹下的 web.json
		fs.writeFile('dist/web.json', JSON.stringify(newStr), 'utf-8', (err) => {
			if (err != null) {
				console.log('ERROR:', err);
			} else {
				console.log('打包完成');
			}
		});


}

2.设置项目打包脚本

我这里是用vue项目为例子 React、Angular 项目也是差不多的做法

打开项目根目录下的 package.json文件 将scripts下的build 改成

node  automated_scripts/build.js

如下图
请添加图片描述

3.运行项目打包命令

pnpm run build

最终就能在项目打包的dist文件夹下生成一个 web.json文件

我的脚本文件

我这里实现了 获取项目信息 获取当前打包的电脑信息 获取get信息 及打包之前进行校验等功能

import fs from 'fs'; // 引入文件系统
import { execSync } from 'child_process'; // 开启一个子进程
import path from 'path';
import os from 'os';
//import packages from './package.json'
// 获取当前命令行上下文路径
const currentDirectory = process.cwd();

const transferTime = (date) => {
	const currentDate = date ? new Date(date) : new Date();
	const year = currentDate.getFullYear();
	const month = currentDate.getMonth() + 1; // getMonth() 返回的是 0-11,需要加 1
	const dates = currentDate.getDate();
	const hours = currentDate.getHours();
	const minutes = currentDate.getMinutes();
	const seconds = currentDate.getSeconds();
	return `${hours}:${minutes}:${seconds} ${year}-${month}-${dates}`;
};

/**
 * 检查本地是否有未提交的更改
 */
const checkChanges = async () => {
	try {
		//本地分支名称
		const branch = execSync('git rev-parse --abbrev-ref HEAD')
			.toString()
			.trim();
		//本地分支 commit hash
		const hash = execSync('git rev-parse HEAD').toString().trim();
		//远程分支 commit hash
		const remoteHash = execSync(
			`git rev-parse ${branch ? 'origin/' + branch : 'HEAD'}`
		)
			.toString()
			.trim();

		const data = execSync('git status').toString().trim();

		if (
			(data.includes('Changes to be committed') ||
				data.includes('Untracked files') ||
				data.includes('Changes not staged for commit') ||
				data.includes('use "git push" to publish your local commits')) &&
			hash !== remoteHash
		) {
			if (data.includes('Changes not staged for commit')) {
				console.log(
					'\x1B[33m',
					'本地项目有数据有文件未add或未commit,请先保存、提交远程 再进行打包',
					'\x1B[0m'
				);
			}
			if (data.includes('Untracked files')) {
				console.log(
					'\x1B[33m',
					'本地项目有数据有文件add了 但未进行commit,请先保存、提交远程 再进行打包',
					'\x1B[0m'
				);
			}
			if (data.includes('Changes to be committed')) {
				console.log(
					'\x1B[33m',
					'本地项目有数据有文件未add或未commit,请先保存、提交远程 再进行打包',
					'\x1B[0m'
				);
			}
			if (data.includes('use "git push" to publish your local commits')) {
				console.log(
					'\x1B[33m',
					'本地项目有数据有文件未push,请先提交远程 再进行打包',
					'\x1B[0m'
				);
			}
			if (hash !== remoteHash) {
				console.log(
					'\x1B[33m',
					'本地项目与远程分支不一致,请先同步再进行打包',
					'\x1B[0m'
				);
			}
			return 0;
		}
		return 1;
	} catch (error) {
		return 1;
	}
};

async function start() {
	console.log('\x1B[32m', '开始打包项目', '\x1B[0m');

	//版本号获取
	const packageJsonPath = path.join(currentDirectory, 'package.json');
	const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8');
	const packageJson = JSON.parse(packageJsonContent);
	const currentVersion = packageJson.version;
	console.log('\x1B[32m', `版本号:${currentVersion}\n`, '\x1B[0m');

	if (await checkChanges()) {
		// 执行npm打包命令
		execSync('vite build --mode production', {
			stdio: 'inherit',
		});

		// 获取当前git分支名称
		const branchName = execSync('git rev-parse --abbrev-ref HEAD')
			.toString()
			.trim();

		//打包时间
		const date = new Date().toLocaleString();

		// 打印
		console.log(
			'\x1B[33m',
			'------------------------------------------',
			'\x1B[0m'
		);
		console.log(
			'\x1B[32m',
			'\t项目信息:\n' +
				`\t版本号:${currentVersion}\n` +
				`\t打包时间:${date}\n` +
				`\tgit分支名称:${branchName}\n`,
			'\x1B[0m'
		);
		console.log(
			'\x1B[33m',
			'------------------------------------------',
			'\x1B[0m'
		);
		const newStr = {
			'git.build.host': '',
			'git.build.architecture': '',
			'git.build.os': '',
			'git.build.release': '',
			'git.build.time': '',
			'git.build.user.email': '',
			'git.build.user.name': '',
			'git.build.version': '',
		};

		//此处添加打包信息
		newStr['git.build.version'] = currentVersion;
		newStr['git.build.host'] = os.hostname();
		newStr['git.build.architecture'] = os.arch();
		newStr['git.build.os'] = os.type();
		newStr['git.build.release'] = os.release();
		newStr['git.build.time'] = transferTime();

		const branch = execSync('git rev-parse --abbrev-ref HEAD')
			.toString()
			.trim();

		//此处添加git命令
		const gitDataMap = {
			'git.branch': 'git rev-parse --abbrev-ref HEAD',
			'git.commit.id': `git rev-parse --verify ${
				branch ? 'origin/' + branch : 'HEAD'
			}`,
			'git.commit.id.abbrev': `git rev-parse --short ${
				branch ? 'origin/' + branch : 'HEAD'
			}`,
			'git.commit.message.full': `git log -1 ${
				branch ? 'origin/' + branch : ''
			} --format="%B"`,
			'git.commit.message.short': `git log -1 ${
				branch ? 'origin/' + branch : ''
			} --format="%s"`,
			'git.commit.time': `git log -1 ${
				branch ? 'origin/' + branch : ''
			} --format="%cd"`,
			'git.commit.user.email': `git log -1 ${
				branch ? 'origin/' + branch : ''
			} --format="%ae"`,
			'git.commit.user.name': `git log -1 ${
				branch ? 'origin/' + branch : ''
			} --format="%an"`,
			'git.dirty': 'git status --porcelain',
			'git.remote.origin.url': 'git remote get-url origin',
			'git.total.commit.count': 'git rev-list --count HEAD',
		};

		Object.keys(gitDataMap).forEach((value) => {
			newStr[value] = execSync(gitDataMap[value]).toString().trim();
			if (value === 'git.commit.time') {
				newStr[value] = transferTime(newStr[value]);
			}
		});

		newStr['git.build.user.email'] = newStr['git.commit.user.email'];
		newStr['git.build.user.name'] = newStr['git.commit.user.name'];
		//将日志写入log.txt
		fs.writeFile('dist/web.version', JSON.stringify(newStr), 'utf-8', (err) => {
			if (err != null) {
				console.log('ERROR:', err);
			} else {
				console.log('打包完成');
			}
		});
	}
	// } else {
	//   console.log(
	//     '\x1B[31m',
	//     '本地有未提交的更改,请先提交 再进行打包',
	//     '\x1B[0m',
	//   )
	// }
}

start();


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[足式机器人]Part2 Dr. CAN学习笔记-动态系统建模与分析 Ch02-7二阶系统

本文仅供学习使用 本文参考: B站:DR_CAN Dr. CAN学习笔记-动态系统建模与分析 Ch02-7二阶系统 1. 二阶系统对初始条件的动态响应 Matlab/Simulink - 2nd Order Syetem Response to IC2. 二阶系统的单位阶跃响应 2nd Order System Unit Step Response3. 二…

UniRepLKNet实战:使用UniRepLKNet实现图像分类任务(一)

文章目录 摘要安装包安装timm 数据增强Cutout和MixupEMA项目结构计算mean和std生成数据集一些问题 摘要 大核卷积神经网络(ConvNets)近年来受到广泛关注,但仍存在两个关键问题需要进一步研究。首先,目前的大型卷积神经网络架构大…

C++枚举类型可以作为返回值类型吗

当然&#xff1a; #include <iostream> // 定义一个枚举类型 enum class Color { RED, GREEN, BLUE }; // 函数返回枚举类型 Color getRandomColor() { static int nextColorIndex 0; Color color Color(nextColorIndex); nextColorIndex; if (nextColor…

Vue入门三(表单控制|购物车案例|v-model进阶|与后端交互|计算属性|监听属性|Vue生命周期)

文章目录 一、表单控制二、购物车案例三、v-model进阶四、与后端交互跨域问题解决&#xff0c;三种交互方法跨域问题详解1-CORS&#xff1a;后端代码控制&#xff0c;上面案例采用的方式1) 方式一&#xff1a;后端添加请求头2) 方式二&#xff1a;编写中间件3) 方式三&#xff…

杨中科 .NET Core 第一部分.NET Standard

1)不讲C#基础语法和NET基础类库(不需要学过ASPNET等)。需要懂HTML、JavaScript、数据库等。后续会录制基础视频 2)使用Visual Studio 2019 .NET .NET Framework Windows 程序 .NET Core 跨平台程序 .NET Standard 上述两者 遵从的标准 .NET5 开始上述统称为 .NET 新建.NET Sta…

解决CDN的网站后台无法获取访客真实ip的问题

宝塔的面板&#xff0c;网站后台获取到的不是访客的真实 ip &#xff0c;而是 CDN 的 ip &#xff0c;这给站长造成了不少影响&#xff0c;例如通过ip地址判定的设置都不准确&#xff0c;甚至假如网站被攻击&#xff0c;对方的真实ip地址都记录不到。 这个问题如何解决&#xf…

爬虫网易易盾滑块及轨迹算法案例:某乎

声明&#xff1a; 该文章为学习使用&#xff0c;严禁用于商业用途和非法用途&#xff0c;违者后果自负&#xff0c;由此产生的一切后果均与作者无关 一、滑块初步分析 js运行 atob(‘aHR0cHM6Ly93d3cuemhpaHUuY29tL3NpZ25pbg’) 拿到网址&#xff0c;浏览器打开网站&#xff0…

华云安攻击面发现及管理平台体验

省流&#xff1a; 无需【立即咨询】即可体验&#xff0c;开通即可查看演示数据&#xff0c;公开报价 界面&#xff1a; 界面简洁&#xff0c;要点清晰&#xff0c;可以清晰的看到暴露面及攻击面信息 功能&#xff1a; 资产发现&#xff1a;主域名发现、子域名发现、 IP 发现…

Qt 窗口阴影边框

环境&#xff1a;Qt 5.15 VS2019 方法一&#xff1a;QGraphicsDropShadowEffect 实现方法参考链接&#xff1a;https://blog.csdn.net/goforwardtostep/article/details/99549750 使用此方法添加窗口阴影&#xff0c;会出现警告信息&#xff1a; 且窗口最大化与还原切换时会…

Vue.js设计与实现阅读-3

Vue设计与实现阅读-3 1、声明式描述UI2、渲染器3、组件4、模板的工作原理5、Vue.js 是各个模块组成的有机整体 前言 前面一章我们了解了&#xff0c;开发体验是衡量一个框架的重要指标之一。提供友好的警告信息至关重要&#xff0c;但是越详细的警告信息&#xff0c;意味着框架…

【SpringCloud】之网关应用(进阶使用)

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是君易--鑨&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的博客专栏《SpringCloud开发之网关应用》。&#x1f3af;&a…

独立站上传产品的方式有哪些?如何快速上品?采集、同步、复制

简介&#xff1a; 搭建新独立站时&#xff0c;传统的复制粘贴将花费大量时间和精力且效率低下&#xff1b;而借助本应用&#xff0c;可有效地避免不必要的人力浪费。只需简单的几个步骤&#xff0c;加上少量的等待时间&#xff0c;即可轻松地将店铺数据从任何商店复制到您的商…

JAVA基础学习笔记-day16-网络编程

JAVA基础学习笔记-day16-网络编程 1. 网络编程概述1.1 软件架构1.2 网络基础 2. 网络通信要素2.1 如何实现网络中的主机互相通信2.2 通信要素一&#xff1a;IP地址和域名2.2.1 IP地址2.2.2 域名 2.3 通信要素二&#xff1a;端口号2.4 通信要素三&#xff1a;网络通信协议 3. 谈…

2024洗地机哪个牌子值得买?洗地机选购指南

在清洁家电的这个市场&#xff0c;洗地机可以说是勇往直前的&#xff0c;不仅在于它高效的深度清洁&#xff0c;还有要考虑它的时间&#xff0c;以及省力方面。在这个洗地机的市场不断地越做越大中&#xff0c;我们在考虑洗地机的配置以及性能上往往没有任何头绪。无线洗地机在…

全链路压力测试有哪些主要作用

全链路压力测试是在软件开发和维护过程中不可或缺的一环&#xff0c;尤其在复杂系统和高并发场景下显得尤为重要。下面将详细介绍全链路压力测试的主要作用。 一、全链路压力测试概述 全链路压力测试是指对软件系统的全部组件(包括前端、后端、数据库、网络、中间件等)在高负载…

redis的使用、打开、关闭的详细介绍

redis的使用、打开、关闭的详细介绍 1.安装redis cd / cd opt/ wget https://download.redis.io/releases/redis-5.0.5.tar.gz 2.解压redis tar xzf redis-5.0.5.tar.gz 3.执行make cd redis-5.0.5/ make 如果出现找不到make的情况就yum install -y make 如果没有gcc就…

phpstorm配置ftp

1 选择设置ftp 2设置自动上传

PACS医学影像报告管理系统源码带CT三维后处理技术

PACS从各种医学影像检查设备中获取、存储、处理影像数据&#xff0c;传输到体检信息系统中&#xff0c;生成图文并茂的体检报告&#xff0c;满足体检中心高水准、高效率影像处理的需要。 自主知识产权&#xff1a;拥有完整知识产权&#xff0c;能够同其他模块无缝对接 国际标准…

Java BIO、NIO(通信/群聊系统、零拷贝)、AIO

Java BIO、NIO(通信/群聊系统、零拷贝)、AIO BIO、NIO、AIO特点和场景 BIO&#xff08;Blocking I/O&#xff09;、NIO&#xff08;Non-blocking I/O&#xff09;、AIO&#xff08;Asynchronous I/O&#xff09;是Java中用于处理I/O操作的三种不同的I/O模型&#xff0c;它们具…

Selenium自动化程序被检测为爬虫,怎么屏蔽和绕过

Selenium 操作被屏蔽 使用selenium自动化网页时&#xff0c;有一定的概率会被目标网站识别&#xff0c;一旦被检测到&#xff0c;目标网站会拦截该客户端做出的网页操作。 比如淘宝和大众点评的登录页&#xff0c;当手工打开浏览器&#xff0c;输入用户名和密码时&#xff0c…