從零構建一個服務器環境前端項目自動更新部署服務(上)

今天咱們來從零構建一個簡易的前端自動部署項目,爲了方便你們理解,除了基礎依賴,儘可能不使用其餘第三方插件(我連ui庫都沒裝),儘可能減小學習成本,項目中用到了pikaz-shell,一個操做shell插件,對此有疑惑的話能夠前往我以前的pikaz-shell文章查看。前端

項目目標

搭建一個服務器前端項目自動部署api服務,搭建一個部署平臺,經過界面操做完成項目部署。vue

文件結構

首先建立一個結構以下的文件夾,並切換到api文件夾,執行npm init -y初始化node

├─api
│  ├─app.js
│  └─base.json
└─admin
複製代碼

api編寫

切換到api文件夾linux

在package.json文件中加入項目所需依賴nginx

"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安裝全部依賴git

app.js

打開app.js文件,編寫所需接口。github

寫入koa一個基礎架構,引入koa和koa路由,處理跨域(由於個人測試環境都是部署在內網服務器上,因此跨域設置所有經過,若是須要個性化設置,則能夠本身去koa2-cors倉庫瞭解),解析post請求中的body(偷懶,全部請求都使用post方式~~~),以及其餘所需功能模塊,端口爲3000,可自行修改app.listen(3000)爲其餘端口。vue-cli

// 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文件當作一個微型數據庫,寫入shell

{
  "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替換爲對應的命令便可,若是項目須要切換分支,可手動切換,或者本身再寫個切換分支的接口,由於篇幅的緣由在此就很少寫了,只完成最基礎的接口服務。

項目地址

github.com/pikaz-18/pi…

最後

nginx配置修改放在下篇講,若是所有放在本篇太臃腫了(其實我也想再水一篇)。

本項目只是一個極簡實現(只爲了讓你們對思路看的更清楚),實現了一個測試環境服務器端的前端項目自動添加、修改、刪除、查詢、構建,由於我是使用在內網服務器環境中的,因此我也沒作帳號驗證,若是須要的話可自行添加如jwt驗證等驗證方式,另外錯誤處理也基本沒作太多,若是想要更完善的錯誤處理,也可自行添加。

若是以爲對你有幫助的話,請點個贊吧。

相關文章
相關標籤/搜索