webpack自动打包、上传服务器

322 阅读2分钟

使用FileManagerPlugin插件自动压缩

1. 安装FileManagerPlugin依赖

yarn add filemanager-webpack-plugin@^5.0.0 --dev

2. vue.config.js 中配置使用

// 先引入插件
const FileManagerPlugin = require('filemanager-webpack-plugin')

  module.exports = {
    publicPath: '/vue3-web',
    outputDir: 'dist',
    assetsDir: 'static',
    chainWebpack: (config) => {
      if (process.env.NODE_ENV === 'production') {
        config.plugin('fileManagerPlugin').use(FileManagerPlugin, [{
          events: {
            onEnd: {
              delete: ['./*.zip'],
              archive: [{ source: './dist', destination: './wszx-app.zip' }]
            }
          }
        }])

        config.plugin('progressBar')
          .use(ProgressBarPlugin, [{
            format: 'build [:bar] :percent (:elapsed seconds)',
            clear: false,
            width: 60
          }])
      }
    }
  }

使用ssh2自动上传服务器

const path = require('path')
const Client = require('ssh2').Client

  // 发布环境
  const publishEnv = [
    {
      host: '123.123.123.123',
      password: "*******",
      catalog: 'use/local/server-web/',
      port: '22',
      username: 'root'
    }
  ]

  // 全局配置
  const Config = {
    publishEnv: publishEnv,
    readyTimeout: 20000, // ssh连接超时时间
    deleteFile: true // 是否删除线上上传的dist压缩包
  }

  /**
   * ssh连接
   */
  class SSH {
    constructor({ host, port, username, password, privateKey }) {
      this.server = {
        host,
        port,
        username,
        password,
        privateKey
      }
      this.conn = new Client()
    }

    // 连接服务器
    connectServer() {
      return new Promise((resolve, reject) => {
        const conn = this.conn
        conn
          .on('ready', () => {
            resolve({
              success: true
            })
          })
          .on('error', err => {
            reject({
              success: false,
              error: err
            })
          })
          .on('end', () => {
            // console.log('----SSH连接已结束----')
          })
          .on('close', () => {
            // console.log('----SSH连接已关闭----')
          })
          .connect(this.server)
      })
    }

    // 上传文件
    uploadFile({ localPath, remotePath }) {
      return new Promise((resolve, reject) => {
        return this.conn.sftp((err, sftp) => {
          if (err) {
            reject({
              success: false,
              error: err
            })
          } else {
            sftp.fastPut(localPath, remotePath, (err, result) => {
              if (err) {
                reject({
                  success: false,
                  error: err
                })
              }
              resolve({
                success: true,
                result
              })
            })
          }
        })
      })
    }

    // 执行ssh命令
    execSsh(command) {
      return new Promise((resolve, reject) => {
        return this.conn.exec(command, (err, stream) => {
          if (err || !stream) {
            reject({
              success: false,
              error: err
            })
          } else {
            stream
              .on('close', (code, signal) => {
                resolve({
                  success: true
                })
              })
              .on('data', function (data) {
                console.log(data.toString())
              })
              .stderr.on('data', function (data) {
                resolve({
                  success: false,
                  error: data.toString()
                })
              })
          }
        })
      })
    }

    // 结束连接
    endConn() {
      this.conn.end()
      if (this.connAgent) {
        this.connAgent.end()
      }
    }
  }

  // SSH连接,上传,解压,删除等相关操作
  async function sshUpload(sshConfig, fileName) {
    const sshCon = new SSH(sshConfig)
    const sshRes = await sshCon.connectServer().catch(e => {
      console.error(e)
    })
    if (!sshRes || !sshRes.success) {
      console.error('----连接服务器失败,请检查用户名密码是否正确以及服务器是否已开启远程连接----')
      return false
    }
    console.log('----连接服务器成功,开始上传文件----')
    const uploadRes = await sshCon
      .uploadFile({
        localPath: path.resolve(__dirname, '..', fileName),
        remotePath: sshConfig.catalog + '/' + fileName
      })
      .catch(e => {
        console.error(e)
      })

    if (!uploadRes || !uploadRes.success) {
      console.error('----上传文件失败,请重新上传----')
      return false
    }
    console.log('----上传文件成功,开始解压文件----')

    const zipRes = await sshCon.execSsh(`unzip -oq ${sshConfig.catalog + '/' + fileName} -d ${sshConfig.catalog}`).catch(e => { })
    if (!zipRes || !zipRes.success) {
      console.error('----解压文件失败,请手动解压zip文件----')
      console.error(`----错误原因:${zipRes.error}----`)
    }
    if (Config.deleteFile) {
      console.log('----解压文件成功,开始删除上传的压缩包----')

      // 注意:rm -rf为危险操作,请勿对此段代码做其他非必须更改
      const deleteZipRes = await sshCon.execSsh(`rm -rf ${sshConfig.catalog + '/' + fileName}`).catch(e => { })
      if (!deleteZipRes || !deleteZipRes.success) {
        console.error('----删除文件失败,请手动删除zip文件----')
        console.error(`----错误原因:${deleteZipRes.error}----`)
      }
    }
    // 结束ssh连接
    sshCon.endConn()
  }

  // 执行前端部署
  (async () => {
    const beginTime = new Date().getTime()

    // 压缩包的名字
    const fileName = 'dist.zip'
    if (Config.publishEnv instanceof Array && Config.publishEnv.length) {
      for (let i = 0; i < Config.publishEnv.length; i++) {
        await sshUpload(Config.publishEnv[i], fileName)
      }
    } else {
      await sshUpload(Config.publishEnv, fileName)
    }
    const endTime = new Date().getTime()
    // 消耗时长
    const totalMin = Math.floor(((endTime - beginTime) / 1000 / 60))
    const totalSec = Math.floor(((endTime - beginTime) / 1000 % 60))
    console.log(`----上传耗总时 ${totalMin}${totalSec} 秒----`)
  })()