前端自动化部署(node版)

准备工作

 yarn add ssh2 commander archiver

开搞

在项目根目录建一个文件夹publish

新增两个文件publish-zip.js  ,publish.js

publish-zip.js内容如下


const fs = require('fs')

const archiver = require('archiver')

const env = require('../config/prod.env')


module.exports = function () {


  var output = fs.createWriteStream(`publish/${env.DEFAULT_HOST.name}.zip`)

  var archive = archiver('zip')

  output.on('close', function () {


    console.log('compress completed...ready upload')

    require('./publish.js')()

  })

  output.on('end', function () {

  })

  archive.on('error', function (err) {

    throw err

  })

  archive.pipe(output)

  archive.glob('./dist' + '/**')

  archive.finalize()

}

 publish.js内容如下


const env = require('../config/prod.env')

const chalk = require('chalk')

var Client = require('ssh2').Client

var conn = new Client()

var fs = require('fs')

const user = {

  host: env.DEFAULT_HOST.host,

  port: 22,

  username: env.DEFAULT_HOST.user,

  // password: env.DEFAULT_HOST.password
  privateKey: fs.readFileSync('./publish/id_rsa')

}

/**

 * 1.进入目录

 * 2.删除旧的备份项目

 * 3.将原项目名称加上bak标志为备份文件

 * 4.解压缩上传的zip文件并将名称改为项目名称

 * 5.删除zip文件

 * 6.退出

 * @type {string[]}

 */

const uploadShellList = [

  `cd ${env.DEFAULT_HOST.path}\n`,

  `rm -rf ${env.DEFAULT_HOST.name}.bak\n`,

  `mv ${env.DEFAULT_HOST.name} ${env.DEFAULT_HOST.name}.bak\n`,

  `unzip ${env.DEFAULT_HOST.name}.zip\n`,

  `mv dist ${env.DEFAULT_HOST.name}\n`,

  `rm -rf ${env.DEFAULT_HOST.name}.zip\n`,

  `exit\n`

]

const params = {file: `./publish/${env.DEFAULT_HOST.name}.zip`, target: `${env.DEFAULT_HOST.path}/${env.DEFAULT_HOST.name}.zip`}

/**

 * 上传文件

 * @param conn

 * @param params

 * @constructor

 */

function UploadFile (conn, params) {

  const file = params.file

  const target = params.target

  if (!conn) {

    return

  }

  conn.sftp(function (err, sftp) {

    if (err) {

      throw err

    }

    sftp.fastPut(file, target, {}, function (err, result) {

      if (err) {

        console.log(chalk.red(err.message))

        throw err

      }

      Shell(conn)

    })

  })

}

function Ready () {

  conn.on('ready', function () {

    console.log('Client :: ready')

    UploadFile(conn, params)

  }).connect(user)

}

/**

 * 上传完成后服务器需要执行的内容

 * 删除本地压缩文件

 * @param conn

 * @constructor

 */

function Shell (conn) {

  conn.shell(function (err, stream) {

    if (err) throw err

    stream.on('close', function () {

      console.log('Stream :: close')

      conn.end()

      fs.unlinkSync(`./publish/${env.DEFAULT_HOST.name}.zip`)

    }).on('data', function (data) {

      console.log('STDOUT: ' + data)

    }).stderr.on('data', function (data) {

      console.log('STDERR: ' + data)

    })

    stream.end(uploadShellList.join(''))

  })

}

module.exports = function () {

  try {

    Ready()

  } catch (err) {

    console.log(err)

  }

}

这里登陆方式分两种 密码登陆和秘钥登录

 // password: env.DEFAULT_HOST.password
  privateKey: fs.readFileSync('./publish/id_rsa')

 在config/prod.env.js 修改如下

"use strict";

const REMOTE_SERVER = '0.0.0.0'

const DEFAULT_HOST = { host: REMOTE_SERVER, user: 'root',password:'', key: '', name: 'demo', path: '/home' }

module.exports = {
  
  REMOTE_HOST: REMOTE_SERVER,

  DEFAULT_HOST: DEFAULT_HOST,

};

name是项目名,path是服务器路径

build/build.js修改如下

'use strict'
require('./check-versions')()
const program = require('commander')
process.env.NODE_ENV = 'production'

const ora = require('ora')
const rm = require('rimraf')
const path = require('path')
const chalk = require('chalk')
const webpack = require('webpack')
const config = require('../config')
const webpackConfig = require('./webpack.prod.conf')

const spinner = ora('building for production...')
spinner.start()
program
  .version('0.0.1')
  .option('-p, --publish', 'Publish Remote')
  .parse(process.argv)

rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
  if (err) throw err
  webpack(webpackConfig, (err, stats) => {
    spinner.stop()
    if (err) throw err
    process.stdout.write(stats.toString({
      colors: true,
      modules: false,
      children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build.
      chunks: false,
      chunkModules: false
    }) + '\n\n')

    if (stats.hasErrors()) {
      console.log(chalk.red('  Build failed with errors.\n'))
      process.exit(1)
    }

    console.log(chalk.cyan('  Build complete.\n'))
    console.log(chalk.yellow(
      '  Tip: built files are meant to be served over an HTTP server.\n' +
      '  Opening index.html over file:// won\'t work.\n'
    ))
    if (program.publish) {
      console.log('-----');
      require('../publish/publish-zip')()
    }
  })
})

新增内容

const program = require('commander')
==========================
program
  .version('0.0.1')
  .option('-p, --publish', 'Publish Remote')
  .parse(process.argv)

============================

if (program.publish) {
      console.log('-----');
      require('../publish/publish-zip')()
}

在package.json 新增命令 

"publish": "node build/build.js -p"

执行命令npm run publish 就可以自动打包上传到服务器了

还没完

 秘钥登录

 在服务器执行命令

ssh-keygen -t rsa

#    Enter file in which to save the key (/root/.ssh/id_rsa): #默认即可
#    Enter passphrase (empty for no passphrase): #输入密码 为空就行
#    Enter same passphrase again: #再输入一遍保护密码 为空就行

会生成两个文件/root/.ssh/id_rsa.pub (公钥),/root/.ssh/id_rsa(私钥)

如果输入密码秘钥文件就有被加密了需要转成ppk文件

导入公钥 

cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys

 在/etc/ssh/sshd_config文件修改配置

RSAAuthentication yes 
PubkeyAuthentication yes 
AuthorizedKeysFile .ssh/authorized_keys 

然后重启服务器

把/root/.ssh/id_rsa(私钥)文件下载到本地用于登录

你可能感兴趣的:(前端自动化,自动化部署)