前端自动化打包部署服务器备份jQuery/webpack/node

场景:

前端工程发布部署 有时需区分测试环境 生产环境 预发行环境等等
主流方式 jinkens/ftp工具/命令行ssh 或者手动
试试这个

node环境实现前端工程一键自动化打包,服务器备份,部署
演示效果(实际命令 npm run deploy)

在这里插入图片描述


配置:

目录结构

deploy.js 自动部署主程序
deployConfig.js 自动部署配置文件
deploy文件夹 自动打包部署备份所需配置文件等
在这里插入图片描述

步骤:

node 下安装几个工具库

archiver 文件归档压缩工具
inquirer 命令行交互
node-ssh node下加密网络传输 用于连接服务器
runjs 执行命令行

npm install archiver --save
npm i inquirer --save
npm i node-ssh --save
npm install runjs --save-dev

在这里插入图片描述

部署主文件
/**
 * @author deep1nBlur
 * @email 
 * @create date 2020-11-11 17:09:45
 * @modify date 2020-11-13 17:17:19
 * @desc [自动部署主程序]
 */
const deployConfig = require('./deployConfig')
const helper = require('./deploy/helper')
const compressFile = require('./deploy/compressFile')
const sshServer = require('./deploy/ssh')
const uploadFile = require('./deploy/uploadFile')
const runCommand = require('./deploy/handleCommand')
const path = require('path')
const projectHelper = helper.projectHelper
const {
  run
} = require('runjs') // node 执行终端


// 主程序
async function main() {
  console.log('\033[40;31m ###### \033[40;31m 注意!!! 确认 BASE_API 配置正确 && 执行 npm 打包脚本 再进行部署!(ctrl+c)可退出进程!\033[0m')
  try {
    console.log('\033[41;37m START \033[40;35m ================================PARK-WEB-自动部署================================\033[0m')
    const SELECT_CONFIG = (await projectHelper(deployConfig)).value // 所选部署项目的配置信息
    console.log('--------------------------------项目名称' + SELECT_CONFIG.name)
    const localFile = path.join(__dirname, '/') + SELECT_CONFIG.targetFile // 待上传本地文件

    SELECT_CONFIG.openCompress ? await compressFile(SELECT_CONFIG.targetDir, localFile) : '' // 压缩
    await sshServer.connectServe(SELECT_CONFIG.ssh) // 连接
    await uploadFile(sshServer.ssh, SELECT_CONFIG, localFile) // 上传
    await runCommand(sshServer.ssh, 'unzip -o ' + SELECT_CONFIG.targetFile, SELECT_CONFIG.deployDir) // 解压
    await run('rm -rf ' + SELECT_CONFIG.targetDir) //删除本地
    await run('rm -r ' + SELECT_CONFIG.targetFile) //删除本地
  } catch (err) {
    console.log('部署过程出现错误!', err)
  } finally {
    console.log('\033[42;30m DONE \033[40;35m ===========================项目-自动部署已完成!=============================\033[0m')
    process.exit()
  }
}

main()

部署服务器配置文件
自行配置 看注释
/**
 * @author deep1nBlur
 * @email 
 * @create date 2020-11-11 17:10:53
 * @modify date 2020-11-13 17:17:27
 * @desc [自动部署配置文件]
 * 说明:
  ssh: 连接服务器用户信息
  targetDir: 需要压缩的文件目录(启用本地压缩后生效)
  targetFile: 指定上传文件名称(config.js同级目录)
  openCompress: 关闭后,将跳过本地文件压缩,直接上传同级目录下指定文件
  openBackUp: 开启后,若远端存在相同目录,则会修改原始目录名称,不会直接覆盖
  deployDir: 指定远端部署地址
  releaseDir: 指定远端部署地址下的发布目录名称
  bakDir:远端服务器 备份目录
 */

const deployConfig = [{
    name: '测试环境',
    ssh: {
      host: '测试环境服务器ip',
      port: 测试端口,
      username: '用户名',
      password: '密码',
      // privateKey: 'E:/id_rsa', // ssh私钥(不使用此方法时请勿填写, 注释即可)
      passphrase: '' // ssh私钥对应解密密码(不存在设为''即可)
    },
    targetDir: 'dist', // 目标压缩目录(可使用相对地址)
    targetFile: 'dist.zip', // 目标文件
    openCompress: true, // 是否开启本地压缩
    openBackUp: true, // 是否开启远端备份
    deployDir: '/xxx/xxxxx/xxxxxx' + '/', // 远端目录
    releaseDir: 'xxxx', // 发布目录
    backDir: 'BACKUP' // 远程服务器备份目录
  },
  {
    name: '生产环境',
    ssh: {
      host: '生产环境服务器ip',
      port: 生产端口,
      username: '用户名',
      password: '密码',
      passphrase: ''
    },
    targetDir: 'admin',
    targetFile: 'admin.zip',
    openCompress: true,
    openBackUp: true,
    deployDir: '/xxx/xxxxx/xxxxx/xxxx' + '/',
    releaseDir: 'xxxxx',
    backDir: 'bak'
  }
]

module.exports = deployConfig

压缩本地文件 compressFile.js
/**
 * @author deep1nBlur
 * @email 
 * @create date 2020-11-11 17:06:26
 * @modify date 2020-11-12 15:24:59
 * @desc [压缩本地文件]
 */
const fs = require('fs')
const archiver = require('archiver')

function compressFile(targetDir, localFile) {
  return new Promise((resolve, reject) => {
    fs.open(targetDir, 'r', (err, fd) => {
      if (err) {
        if (err.code === 'ENOENT') {
          console.error('本地部署文件不存在')
          return
        }
        throw err
      }
      console.log('--------------------------------正在压缩...')
      const output = fs.createWriteStream(localFile) // 创建文件写入流
      const archive = archiver('zip', {
        zlib: {
          level: 9
        } // 设置压缩等级
      })
      output.on('close', () => {
        resolve(
          console.log('--------------------------------压缩完成! 共计 ' + (archive.pointer() / 1024 / 1024).toFixed(3) + 'MB')
        )
      }).on('error', (err) => {
        reject(console.log('%c 2-项目-自动部署 压缩失败!', 'color:#ff1744;', err))
      })
      archive.pipe(output) // 管道存档数据到文件
      archive.directory(targetDir, 'admin') // 存储目标文件并重命名
      archive.finalize() // 完成文件追加 确保写入流完成
    })
  })
}

module.exports = compressFile

调用远端命令 handleCommand.js
/**
 * @author deep1nBlur
 * @email 
 * @create date 2020-11-11 17:06:54
 * @modify date 2020-11-12 13:26:21
 * @desc [调用远端命令]
 */

// run linux shell(ssh对象、shell指令、执行路径)
function runCommand(ssh, command, path) {
  return new Promise((resolve, reject) => {
    ssh.execCommand(command, {
      cwd: path
    }).then((res) => {
      if (res.stderr) {
        reject(console.error('命令执行发生错误:' + res.stderr))
        process.exit()
      } else {
        resolve(console.log('--------------------------------执行指令:' + command))
      }
    })
  })
}

module.exports = runCommand

命令行选择交互提示 helper.js
/**
 * @author deep1nBlur
 * @email 
 * @create date 2020-11-11 17:07:47
 * @modify date 2020-11-12 13:26:26
 * @desc [部署项目选择提示]
 */

const inquirer = require('inquirer')
// 项目选择
const selectProjectName = 'PROJECT_NAME'
const projectOptions = [{
  type: 'list',
  name: selectProjectName,
  message: '上下键=>选择要部署的项目名称',
  choices: []
}]
// 部署方式选择
const selectDeployMode = 'DEPLOY_TYPE'
const deployModeOptions = [{
  type: 'list',
  name: selectDeployMode,
  message: 'Which deployment mode do you want to use?',
  choices: [{
    name: 'legacy'
  }]
}]
// 云端编译选择
const selectBuildMode = 'BUILD_MODE'
const buildModeOptions = [{
  type: 'list',
  name: selectBuildMode,
  message: 'Which dir do you want to upload?',
  choices: [{
    name: 'admin'
  }]
}]

// 项目选择提示窗
function projectHelper(config) {
  return new Promise((resolve, reject) => {
    initHelper(config) // init helper
    inquirer.prompt(projectOptions).then(answers => {
      resolve({
        value: findInfoByName(config, answers[selectProjectName])
      }) // 查找所选配置项
    }).catch((err) => {
      reject(console.error('helper显示或选择出错!'.error, err))
    })
  })
}

// 部署方式选择提示窗
function deployModeHelper() {
  return new Promise((resolve, reject) => {
    inquirer.prompt(deployModeOptions).then(answers => {
      resolve(answers[selectDeployMode])
    }).catch((err) => {
      reject(console.error('helper显示或选择出错!'.error, err))
    })
  })
}

// 远端源码编译提示窗
function buildModeHelper() {
  return new Promise((resolve, reject) => {
    inquirer.prompt(buildModeOptions).then(answers => {
      resolve(answers[selectBuildMode])
    }).catch((err) => {
      reject(console.error('helper显示或选择出错!'.error, err))
    })
  })
}
function initHelper(config) {
  for (const item of config) {
    projectOptions[0].choices.push(item.name)
  }
  // 检查是否存在相同name
  if (new Set(projectOptions[0].choices).size !== projectOptions[0].choices.length) {
    console.error('请检查配置信息,存在相同name!'.warn)
    process.exit()
  }
}

// 查找符合条件的配置项
function findInfoByName(config, name) {
  for (const item of config) {
    if (item.name === name) {
      return item
    }
  }
}

module.exports = {
  projectHelper,
  deployModeHelper,
  buildModeHelper
}

SSH连接服务器 ssh.js
/**
 * @author deep1nBlur
 * @email 
 * @create date 2020-11-11 17:08:03
 * @modify date 2020-11-12 13:26:29
 * @desc [连接远端务器]
 */

const {
  NodeSSH
} = require('node-ssh')
const ssh = new NodeSSH()

function connectServe(sshInfo) {
  return new Promise((resolve, reject) => {
    ssh.connect({
      ...sshInfo
    }).then(() => {
      resolve(console.log('--------------------------------' + sshInfo.host + '连接成功!'))
    }).catch((err) => {
      reject(console.log('--------------------------------' + sshInfo.host + '连接失败!', err))
    })
  })
}

module.exports = {
  ssh,
  connectServe
}

本地文件上传服务器 uploadFile.js
/**
 * @author deep1nBlur
 * @email 
 * @create date 2020-11-11 17:08:19
 * @modify date 2020-11-13 09:12:53
 * @desc [上传本地文件]
 */

const runCommand = require('./handleCommand')
// 获取当前时间
function getCurrentTime() {
  const date = new Date()
  const yyyy = date.getFullYear()
  const MM = coverEachUnit(date.getMonth() + 1)
  const dd = coverEachUnit(date.getDate())
  const HH = coverEachUnit(date.getHours())
  const mm = coverEachUnit(date.getMinutes())
  const ss = coverEachUnit(date.getSeconds())
  return `${yyyy}-${MM}-${dd}_${HH}_${mm}_${ss}`
}

// 转换时间中一位至两位
function coverEachUnit(val) {
  return val < 10 ? '0' + val : val
}
// 文件上传(ssh对象、配置信息、本地待上传文件)
async function uploadFile(ssh, config, localFile) {
  return new Promise((resolve, reject) => {
    handleSourceFile(ssh, config)
    console.log('--------------------------------开始文件上传...')
    ssh.putFile(localFile, config.deployDir + config.targetFile).then(async () => {
      resolve(console.log('--------------------------------文件上传完成'))
    }, (err) => {
      reject(console.error('--------------------------------文件上传失败!', err))
    })
  })
}

// 处理源文件(ssh对象、配置信息)
async function handleSourceFile(ssh, config) {
  if (config.openBackUp) {
    console.log('--------------------------------执行远程备份...')
    //  将部署文件夹 移动到 备份目录 并更名时间后缀
    await runCommand(
      ssh,
      `
      if [ -d ${config.releaseDir} ];
      then 
      mv ${config.targetFile} ${config.backDir}/${config.releaseDir}_${getCurrentTime() + '.zip'}
      fi
      `,
      config.deployDir)
  } else {
    console.log('%c 5-项目-自动部署-未开启远端备份!', 'color:#ff1744;')
    await runCommand(
      ssh,
      `
      if [ -d ${config.releaseDir} ];
      then mv ${config.releaseDir} /tmp/${config.releaseDir}_${getCurrentTime()}
      fi
      `,
      config.deployDir)
  }
}

module.exports = uploadFile

npm脚本命令配置 package.json[“scripts”]
"deploy": "npm run build && node deploy.js",

运行自动部署

npm run deploy

在这里插入图片描述


芜湖 起飞~

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在编写和测试 JavaScript 代码时,确实不乏非常好的选择。不管怎样,代码编辑器通常倾向于令人讨厌的功能组合,对于初学者以及仅想尝试使用 JavaScript 中的新事物的开发人员而言,并不是最佳的解决方案。 JavaScript 代码编辑器 RunJs 中文版JavaScript 代码编辑器 RunJs 中文版 解决此问题的方法可能是 RunJS,它是一种极简主义的 JavaScript 暂存器,它提供了一种直接从您的计算机桌面编写和测试 JavaScript 代码的可访问且无畏的方式。 简单的 JS 编辑器,可供初学者和专家使用 如前所述,此应用程序背后的整个想法应尽可能简单。因此,该应用程序具有一个简单的 GUI,只有两个面板(一个用于编写代码,一个用于预览输出),而其他方面则不多。 当然,编辑器确实具有一些人们可能期望的基本功能,例如语法突出显示和缩进,以及实时代码预览功能(也可以将其关闭以允许您手动执行代码)。 绝对有更多的东西会让您思考 尽管总体上很简单,但是编辑器确实提供了不错的自定义功能。例如,从“设置”部分,您可以更改从 GUI 主题到字体及其大小的所有内容。此外,您可以选择使用行编号还是换行,以及如何处理所谓的不可见字符。 令人惊讶的是,您还可以扩展应用程序的基本功能。例如,您可以从其他 JavaScript 项目安装 NPM 软件包,导入节点模块,以及更改工作目录。 RunJS –创意小 JS 项目的理想场所 总而言之,如果您只是在寻找一个简单的 JS 代码编辑器来尝试基本的思想,而无需处理典型代码编辑器的复杂性就让您的创造力疯狂奔放,那么 RunJS 就是完美的选择。在测试过程中,我们发现的唯一小问题是该应用程序有时难以更改 UI 主题,需要多次重启。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值