今天我们来从零构建一个简易的前端自动部署项目,为了方便大家理解,除了基础依赖,尽量不使用其他第三方插件(我连ui库都没装),尽量减少学习成本,项目中用到了pikaz-shell,一个操作shell插件,对此有疑惑的话可以前往我之前的pikaz-shell文章查看。
项目目标
搭建一个服务器前端项目自动部署api服务,搭建一个部署平台,通过界面操作完成项目部署。
文件结构
首先创建一个结构如下的文件夹,并切换到api文件夹,执行npm init -y初始化
├─api
│ ├─app.js
│ └─base.json
└─admin
api编写
切换到api文件夹
在package.json文件中加入项目所需依赖
"dependencies": {
"koa": "^2.13.0",
"koa-bodyparser": "^4.3.0",
"koa-router": "^9.0.1",
"koa2-cors": "^2.0.6",
"pikaz-shell": "^0.1.3"
}
执行npm install安装所有依赖
app.js
打开app.js文件,编写所需接口。
写入koa一个基础架构,引入koa和koa路由,处理跨域(因为我的测试环境都是部署在内网服务器上,所以跨域设置全部通过,如果需要个性化设置,则可以自己去koa2-cors仓库了解),解析post请求中的body(偷懒,所有请求都使用post方式~~~),以及其他所需功能模块,端口为3000,可自行修改app.listen(3000)为其他端口。
// Koa
const Koa = require('koa');
const app = new Koa();
// 跨域设置
const cors = require('koa2-cors');
app.use(cors());
// 路由
const Router = require('koa-router');
const router = new Router();
// 解析body
const bodyParser = require('koa-bodyparser');
app.use(bodyParser());
const fs = require('fs');
const shell = require('pikaz-shell');
// 启动路由
app.use(router.routes()).use(router.allowedMethods())
/*
* api编写
*/
console.log("启动成功")
app.listen(3000);
数据库
因为我们这个项目是非常小的,使用太大的数据库未免有点太浪费了,而且迁移部署很麻烦,所以我们使用之前创建的base.json文件当做一个微型数据库,写入
{
"project": [],
"nginx": {}
}
其中project为项目信息,nginx为nginx配置
接口
查询列表接口
router.post('/list', async ctx => {
const { project, nginx } = JSON.parse(fs.readFileSync('./base.json', 'utf-8'));
ctx.body = { code: 200, data: { project, nginx }, message: '查询成功' };
})
读取base.json文件,取出其中的project和nginx值返回
添加项目接口
/**
* @name: 添加项目
* @param {String} name/项目名称
* @param {String} git/项目git地址
* @param {String} path/项目所在文件夹位置
* @param {String} build/打包命令
* @return:
*/
router.post('/add', async ctx => {
const { name, git, path, build } = ctx.request.body
const data = JSON.parse(fs.readFileSync('./base.json', 'utf-8'));
const gitProject = data.project.find(item => item.name === name)
if (gitProject) {
ctx.body = { code: 500, data: null, message: '已存在相同名称的项目' };
return
}
// 工程文件名
const n = git.split('/')
const projectName = n[n.length - 1].replace('.git', '')
// clone项目并安装依赖打包
const result = await shell([{ cmd: [`git clone ${git}`], path }])
if (result === true) {
// 添加入配置中
data.project.push({ name, git, path, projectName, build })
fs.writeFileSync('./base.json', JSON.stringify(data))
ctx.body = { code: 200, data: null, message: '添加成功' };
} else {
ctx.body = { code: 500, data: null, message: '添加失败' };
}
})
接收四个参数,分别为项目名称,项目git地址,项目所在文件夹位置,打包命令,我们使用项目名称作为主键,不可重复,如果重复则返回重复错误信息,之后使用pikaz-shell插件执行git clone项目,从git地址中获取clone下来的文件夹名称,并添加进配置中,之后将项目信息写入base.json数据库中。
编辑项目接口
/**
* @name: 编辑
* @param {String} name/项目名称
* @param {String} git/项目git地址
* @param {String} path/项目所在文件夹位置
* @param {String} build/打包命令
* @return:
*/
router.post('/edit', async ctx => {
const { name, git, path, build } = ctx.request.body
const data = JSON.parse(fs.readFileSync('./base.json', 'utf-8'));
const index = data.project.findIndex(item => item.name === name)
if (index === -1) {
ctx.body = { code: 500, data: null, message: `不存在${name}项目` };
return
} else {
// 配置修改项目
data.project[index] = { ...data.project[index], git, path, build }
fs.writeFileSync('./base.json', JSON.stringify(data))
ctx.body = { code: 200, data: null, message: '修改成功' };
}
})
和添加接口类似,接收同样的四个参数,读取base.json数据库,查看是否存在相同项目名称name,不存在则返回错误信息,存在则将对应的项目信息修改(name是主键,不可修改,所以在赋值时并没有将name赋值,而是保留原有的name),之后将处理好的数据写入base.json数据库中。
编辑项目接口
/**
* @name: 删除
* @param {String} name/删除项目的名称
* @return:
*/
router.post('/del', async ctx => {
const { name } = ctx.request.body
const data = JSON.parse(fs.readFileSync('./base.json', 'utf-8'));
const index = data.project.findIndex(item => item.name === name)
if (index === -1) {
ctx.body = { code: 500, data: null, message: `不存在${name}项目` };
} else {
// 删除项目文件
const project = data.project[index]
const result = await shell([{ cmd: [`rd/s/q ${project.projectName}`], path: project.path }])
if (result) {
// 配置删除项目
data.project.splice(index, 1)
fs.writeFileSync('./base.json', JSON.stringify(data))
ctx.body = { code: 200, data: null, message: '删除成功' };
return
}
ctx.body = { code: 500, data: null, message: '删除失败' };
}
})
基本操作和添加修改没太大区别,读取base.json数据库,查找传过来的name,删除该条项目信息,再写入base.json数据库。
构建项目接口
/**
* @name: 构建
* @param {String} name/项目名称
* @return:
*/
router.post('/build', async ctx => {
const { name } = ctx.request.body
// 查找项目
const data = JSON.parse(fs.readFileSync('./base.json', 'utf-8'));
const index = data.project.findIndex(item => item.name === name)
if (index === -1) {
ctx.body = { code: 500, data: null, message: `${name}项目文件不存在` };
} else {
const project = data.project[index]
const path = `${project.path}/${project.projectName}`
if (fs.existsSync(`${path}/node_modules`)) {
// 存在node_modules则删除
await shell([{ cmd: ["rd/s/q node_modules"], path }])
}
// 安装依赖打包
const result = await shell([{ cmd: ["git pull", "npm install", project.build], path }])
if (result === true) {
ctx.body = { code: 200, data: null, message: "build成功" };
} else {
ctx.body = { code: 500, data: null, message: "build失败" };
}
}
})
构建接口接收一个项目名称name参数,查找base.json中porject中的相同name的项目信息,使用项目信息中的路径path和文件夹名称projectName组成项目的绝对定位地址,在项目中查找是否有node_modules依赖文件夹,如果有,则删除;之后进行git pull拉取项目,npm install安装依赖,以及项目信息中的build打包命令。
至此,整个项目构建api服务已完成(nginx部署部分放到下篇)
api调用
如项目的添加api调用
// api服务地址
const api="http://127.0.0.1:3000";
// 添加的项目信息
const addProject={ name: "pikaz-excel-js", git: "https://github.com/pikaz-18/pikaz-excel-js.git", path: "D:\", build: "npm run build" };
// 添加
fetch(`${api}/add`, {
method: 'POST',
body: JSON.stringify(addProject),
headers: {
'Content-Type': 'application/json'
}
}).then(res => {
res.json().then(data => {
if (data.code === 200) {
// 构建
fetch(`${api}/build`, {
method: 'POST',
body: JSON.stringify({ name:addProject.name }),
headers: {
'Content-Type': 'application/json'
}
}).then(res => {
res.json().then(data => {
})
}).catch(err => {
console.log(err)
})
}
})
}).catch(err => {
console.log(err)
})
调用添加/add接口,添加成功后调用/build构建接口,即可完成项目的添加与构建。
可以以此为基础构建一个项目部署界面,也可以在项目根目录中加入一个build.js文件,里面写好请求/build接口的构建请求,在package.json中的打包命令
"scripts": {
"test": "node build.js && vue-cli-service build"
},
加入node build.js,即可在执行npm run test,在项目构建的时候可同时更新测试环境,完成自动更新啦。
admin项目部署界面就不细说了,可直接查看本项目的admin文件夹,因为只是很简单的调取api,相信这一定难不倒聪明的你,。
项目启动
我使用pm2的方式启动,只需切换到api文件夹执行
npm run dev
即可启动,如果不想使用pm2的话,也可以直接启动
node app.js
注意
在使用本项目前,请确保服务器环境安装了git,node,pm2这些必要环境与插件,并且开放了api服务所使用的端口(也可以使用nginx代理),本项目使用的是win系统命令行,如需在linux系统使用,则将rd/s/q删除命令替换为rm -rf,如需使用如yarn或者cnpm,将npm替换为对应的命令即可,如果项目需要切换分支,可手动切换,或者自己再写个切换分支的接口,因为篇幅的原因在此就不多写了,只完成最基础的接口服务。
项目地址
最后
nginx配置修改放在下篇讲,如果全部放在本篇太臃肿了(其实我也想再水一篇)。
本项目只是一个极简实现(只为了让大家对思路看的更清楚),实现了一个测试环境服务器端的前端项目自动添加、修改、删除、查询、构建,因为我是使用在内网服务器环境中的,所以我也没做账号验证,如果需要的话可自行添加如jwt验证等验证方式,另外错误处理也基本没做太多,如果想要更完善的错误处理,也可自行添加。
如果觉得对你有帮助的话,请点个赞吧。