注册
web

写了个自动化打包工具,大大滴解放了电脑性能

前段时间手底下的小伙伴跟我吐槽,说后端一点小改动就马上要包,电脑性能很差一旦run build之后就得等好几分钟的空窗期,被迫摸鱼导致加班,我灵机一动,是不是可以利用服务器的性能,编写自动化构建从而实现让后端、测试点点点,就能得到他们想要的不同版本的包、或者不同分支的构建产物呢?


于是乎就有了我的设计并产出的开源:Sa-io https://github.com/LIAOJIANS/sa-io.git


Sa-io操作流程:新建项目(指定gitURL) => 内部执行(npm install)=> run build => SE(推送Sucesss日志) => publish(指定目标地址)=> dowl (下载专属产物)


image.png


项目架构


1、UI层


image.png


2、逻辑层


image.png
3、数据层


image.png


4、所需环境层


image.png


核心实现逻辑


1、技术清单



  • child_process:创建子进程并执行构建脚本;
  • chokidar: 监听日志文件内容;
  • scp2:建立SSH连接并传输文件;
  • Vue3:UI界面采用VUE3 + TS

2、核心逻辑


Run Build


router.post('/build', [
(() =>
['shell', 'install', 'projectName'].map((fild) =>
body(fild)
.notEmpty()
.withMessage('username or token is null'),
))(),
], (req, res, next) => {
checkBeforRes(next, req, async () => {

const {
shell,
install,
removeNm,
shellContent,
branch,
projectName,
pull,
...onter
} = req.body

if (os.platform() !== 'linux' && shell) {
return new Result(null, 'Running shell scripts must be in a Linux environment!!!')
.fail(res)
}

const curTime = Date.now()
const id = `${projectName}-${curTime}`
const fileName = `${id}.log`
const logPath = path.resolve(__dirname, `../log/${fileName}`)

let status = 'success'

const getHistory = () => getFileContentByName('history', [])

// 生成构建历史
let data = [
...getHistory(),
{
id,
projectName,
buildTime: curTime,
status: '',
branch
}
]

// 生成日志文件
getFileContentByName(
'',
'',
logPath
)

// 写入history基本信息
setFileContentByName(
'history',
data,
true
)

if (removeNm) {
await rmDir(projectName, 'node_modules') // 删除node_modules 防止不同分支不同版本的依赖冲突

rmFile(`${projectName}/package-lock.json`) // 删除安装依赖日志,防止版本缓存
}

if (branch) { // 如果有分支,并且分支不能等于当前分支,否则切换分支并拉取最新
const projects = getFileContentByName('projects')

const project = projects.find(p => p.projectName === projectName)

if (project.branch !== branch) {
try {
if (install) {

rmFile(`${projectName}/package-lock.json`) // 删除安装依赖日志,防止版本缓存
}

await gitCheckoutPro(projectName, branch)

setFileContentByName('projects', [
...projects.map(p => {
if (p.projectName === projectName) {
p.branch = branch
}

return p
})
], true)
} catch (e) {

console.log(e)

setFileContentByName(
'history',
[
...data,
{
projectName,
buildTime: curTime,
status: 'error',
branch
}
],
true
)

res.status(500).send('checkout error!!! Please review the log output!!!!!!')
}

} else if (pull) { // 拉取最新
try {
await gitPullPro(projectName, logPath)
} catch (e) {
res.status(500).send('checkout error!!! Please review the log output!!!!!!')
}
}
}


new Result(`${id}`, 'building, Please review the log output!!!!!!').success(res)

const compressedPro = () => {
status = 'success'
compressed(`${projectName}-${curTime}`, projectName)

console.log('success')
copyFile(
path.resolve(__dirname, `../project/${projectName}/dist`),
path.resolve(__dirname, `../builds/${projectName}-${curTime}`)
)

const {
publish,
...left
} = onter

if (publish) {
publishTragetServer({
...left,
localPath: path.resolve(__dirname, `../builds/${projectName}-${curTime}`)
})
}

}

if (shell) { // 执行sh脚本

setFileContentByName(
projectName,
shellContent,
true,
path.resolve(__dirname, `../project/${projectName}/build.sh`)
)

await shellPro(projectName, logPath)
.then(compressedPro)
.catch(() => {
status = 'error'
console.log('error')
})
} else { // 执行打包工作流
(
await (install ? installAfterBuildPro : buildPro)(projectName, logPath)
.then(compressedPro)
.catch(() => {
status = 'error'
console.log('error')
})
)
}

let newData = getHistory()

newData = newData.map(c => {
if (c.id === id) {
c.status = status
}

return c
})

setFileContentByName(
'history',
newData,
true
)
})
})

UI界面展示


build.gif


history.gif


最后放个项目地址:github.com/LIAOJIANS/s…


作者:大码猴
来源:juejin.cn/post/7445098587808514082

0 个评论

要回复文章请先登录注册