背景
在项目的完整发版过程中,会包含开发、测试、仿真、上线等多个阶段,同时也会对应项目代码的dev、master等多个分支,如果项目上线的地方比较多,拉取的分支会越来越多。项目部署的环境也会有测试、安全测试、仿真、生产等多套环境,为了清晰快速地知道当前环境部署的前端包打包对应的版本信息,可利用 generate-asset-webpack-plugin
插件结合生成版本信息的函数在 webpack 进行打包时自动生成包含版本信息的 json 文件并添加到输出目录。
本文利用此插件生成的静态资源 version.json 中包含 git 分支、最新的 git 提交记录 id、打包时间信息。
一、优点
- 部署时可以通过查看此文件,检查打包时代码分支是否错误,当前分支的代码是否对应远程仓库中最新的提交记录,比如博主的项目在服务器上部署了自动化打包,可通过这个文件比较直观的先排查服务器打包的前端包版本是否有误
- 生产环境可能发布了多个版本之后,项目中可能拉取了许多对应的发版分支,生产环境如果出现问题需要修复,且如果发现问题的时间间隔较久,可能会忘记那一次发版对应的代码是那一套,是何时提供的前端包,有了这个版本信息的 json 文件,就可以快速的知道
二、编码
1.安装插件
npm i generate-asset-webpack-plugin -D
本文中使用的插件版本为 0.3.0
2.配置插件
本文项目是 vue 框架,配置文件为 vue.config.js
const GenerateAssetPlugin = require('generate-asset-webpack-plugin')
// 引入生成 json 文件的 函数,version.js 存放在根目录下
const createCompileVersionJsonFile = require('./version')
module.exports = {
publicPath: './',
// ...
configureWebpack: {
performance: {
hints: false
},
plugins: [
new GenerateAssetPlugin({
filename: 'version.json',
fn: (compilation, cb) => {
cb(null, createCompileVersionJsonFile(compilation))
},
extraFiles: []
})
]
},
}
3.version.js
module.exports = createCompileVersionJsonFile = () => {
// 记录打包时间信息
let d = new Date()
let y = d.getFullYear()
let m = d.getMonth() + 1
let day = d.getDate()
if (m >= 1 && m <= 9) m = '0' + m
if (day >= 0 && day <= 9) day = '0' + day
let now = y + '-' + m + '-' + day + ' ' + d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds()
// git版本
let fs = require('fs')
let gitHEAD = fs.readFileSync('.git/HEAD', 'utf-8').trim()
let ref = gitHEAD.split(': ')[1]
// 最新的git记录 ID
let git = ref ? fs.readFileSync('.git/' + ref, 'utf-8').trim() : gitHEAD
// 打包分支名
let branch = gitHEAD.split('/')[2]
// 这种方式在裸仓库上可能获取不到分支名称,使用以下方式获取
if (!branch) {
let { execSync } = require('child_process')
try {
let refsArr = execSync('git show-ref').toString().trim().split('\n')
// 用当前的 git ID 去匹配拿到最新一条 git ID 和分支的映射关系
let idBranchMapStr = refsArr.find(r => r.startsWith(git))
branch = idBranchMapStr.split('/').pop()
} catch (error) {
console.error('执行命令报错:', error)
}
}
return JSON.stringify({
time: now,
git,
version: branch
})
}
使用 fs.readFileSync('.git/HEAD', 'utf-8').trim()
读取项目的 .git 目录下的 HEAD 文件中的内容,如果是裸仓库,得到的是当前分支的最新的一条提交记录 id,其他情况下正常是得到包含当前分支信息的字符串 ref: refs/heads/dev
,然后截取分支名 ref 之后再通过 fs.readFileSync('.git/' + ref, 'utf-8').trim()
读取当前最新的 git 提交记录。
因项目在服务器上部署 jenkins 打包的代码是裸仓库,分支名称无法获取,所以当分支名无法获取时,使用执行 git 命令 execSync('git show-ref')
的方式读取,得到的是所有分支的 最新一条 git 提交 ID 和分支名的对应关系,然后再根据 .git/HEAD 文件存储的 id 进行匹配对应的分支再进行截取。
注意: 匹配分支名称时可能存在多个分支最新的 git id 相同的情况,此时匹配的分支其实应该是多个,因项目中发版分支的代码很少出现未考虑。如需考虑,可参考以下代码。
let refsArr = execSync('git show-ref').toString().trim().split('\n')
// 分支命名带上发版的日期(打包日期) 如 master-20231215
let idBranchMapStr = refsArr.find(r => r.startsWith(git) && r.endsWith(y + m + day))
branch = idBranchMapStr.split('/').pop()
4.控制台打印版本信息
outputCompile() {
if (process.env.NODE_ENV === 'production') {
let url = location.origin + location.pathname
url = url.replace('index.html', '') + 'version.json'
this.$http.get(url).then(res => {
console.log('编译版本信息')
console.log('Time', res.time)
console.log('Id', res.git)
console.log('Branch', res.version)
})
}
},
此代码生产环境谨慎使用,测试环境等通过这个打印方便快速的定位是否由编译打包不正确,或者团队成员本地代码未提交而引起远程仓库代码在自动化打包后版本对应不上而引起的部分问题。
扩展
- 在 Git 中,裸仓库(Bare
Repository)是一个没有工作目录的仓库,也就是说,它只包含版本历史信息,而不包含未提交的更改或者当前的工作状态。裸仓库通常用于在服务器上存储共享的版本历史,而不用于在本地进行开发工作。 - execSync 方法返回的是一个 Buffer 对象,使用 toString()
方法转换成字符串,参考:execSync