背景
前端在打包的时候, 有时我们需要在master分支里面执行npm run build,在test分支里面执行npm run build --mode test,在dev的临时分支里面不要做任何打包的操作。
我们package.json里面的scripts一般会这样定义:
"build:": "vite build",
"build:test": "vite build --mode test",
再配合上vite.config.js中的配置
build: {
outDir: mode == 'production' ? 'dist' : `dist-${mode}`
}
不同的打包命令打出来对应环境下不同名字的包。
但是这样很容易出错,比如我在master分支里面不小心执行了test的打包。
这时候就希望有点防呆防错的手段能阻止我犯错。
那么我们可以这样做:
基础
"build": "node -e \"const branch = require('child_process').execSync('git rev-parse --abbrev-ref HEAD').toString().trim(); if (branch !== 'master') throw new Error('Not on master branch, aborting build')\" && npm run build:actual",
"build:test": "node -e \"const branch = require('child_process').execSync('git rev-parse --abbrev-ref HEAD').toString().trim(); if (branch !== 'test') throw new Error('Not on dev-test branch, aborting build')\" && npm run build:test:actual",
"build:actual": "vite build",
"build:test:actual": "vite build --mode test",
这里的build后面跟了一长串的代码,简单解释一下就是,先检查一下当前分支的分支名,
如果是master,就允许你执行npm run bild,否则就报错,test同理。
这样就初步实现了我们的需求,只是build后面跟上这么一长串代码,不好看,而且也不便于我们书写。
我们新建文件来执行分支检测,然后在 package.json 的脚本中调用这个文件。
创建一个 check-branch-master.js 文件,然后把build命令改为:
"build": "node check-branch.js && npm run build:actual"
// check-branch-master.js
import { execSync } from 'child_process'
const currentBranch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
if (currentBranch !== 'master') {
throw new Error(`Not on master branch, aborting build`);
}
同理,我们再加一个检测test打包的脚本和命令,就可以了。
这样你在master分支只能执行npm run build,如果执行了npm run build:test会报错,如果在临时的开发环境,无论执行哪个打包命令都会报错。
进阶 pre-scripts
上面我们其实已经初步实现了需求,能够在打包的时候做一下验证,防止执行了错误的打包命令。主要原理是在我们在执行打包命令之前先执行一步验证的操作。
其实npm已经为我们准备了这样的命令:
pre-scripts: 一种在 npm 脚本命令执行之前运行的脚本
我们把 package.json中中的命令改造一下:
"prebuild": "node check-branch-master.js",
"build": "npm run build",
"prebuild:test": "node check-branch-test.js",
"build:test": "npm run build",
这样在npm run build的时候,他就会自动先执行一下prebuild的命令,和上面是一样的效果,只是利用了npm自己的一个机制。
自动化
实现了防呆防错,但是对我们来说还是有心智的负担,能不能一步到位,就一个npm run build命令,他自己去判断在哪个分支,自己调用相应的打包命令。
这里我们先改造一下package.json文件:
"build": "node checkBranch.js",
注意,这里我们只需要一个checkBranck.js文件。
如果想要保留npm run build命令的话,可也以定义一个别的。
接着改造一下checkBranch.js文件
import { execSync } from 'child_process'
const currentBranch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim()
if (currentBranch === 'master') {
execSync('vite build', { stdio: 'inherit' })
} else if (currentBranch === 'dev-test') {
execSync('vite build --mode test', { stdio: 'inherit' })
} else {
throw new Error(
`Not on master branch or dev-test branch, but ${currentBranch} aborting build`
)
}
这里其实就实现了,先判断一下当前的git分支名,然后去调用定义的打包命令或者抛出错误。 这样不管我们在哪个分支,我们都可以去执行npm run build, 都会正确的打包或者提醒你当前分支不要打包。
线上打包 git hooks
上面的方法其实有一点不好,那就是在合并分支的时候,dist和dist-test文件经常会有冲突,每次都要解决。 那我们其实可以采用线上打包的方法,这样就没有dist 和 dist-test文件夹了,合并分支的时候不会有冲突。但是这样带来的问题是,上面说的打包方法都不合适了。那么在服务器上,我们该如何实现自动打包。
答案就是git hooks
首先我们在服务器上项目的根目录上进入目录.git/hooks,新建文件post-merge脚本
添加内容:
#!/bin/sh
# 获取合并操作前的当前分支
PREVIOUS_BRANCH=$(git rev-parse --abbrev-ref HEAD)
# 执行 git pull 操作
git pull
# 获取合并操作后的当前分支
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
# 判断分支是否发生变化,如果没有变化则执行对应命令
if [ "$PREVIOUS_BRANCH" = "$CURRENT_BRANCH" ]; then
case "$CURRENT_BRANCH" in
"master")
npm run build
;;
"test")
npm run build:test
;;
*)
echo "No specific command for branch: $CURRENT_BRANCH"
;;
esac else
echo "Branch changed after merge. No specific command executed."
fi
post-merge钩子会在我们每次执行git pull的时候调用,这样我们每次在服务器上拉取代码的时候就会自动执行打包,实现自动打包,完美解决了上面的所有问题。
这里touch了文件之后,要给文件添加执行权限,chmod 755 post-merge