preface

In previous deployments, packages were generated on the front end and replaced to the server through SFTP. At the beginning, I felt fine, but more times, I felt trouble. Also know there is automatic deployment this thing, but really lazy, this time to get it out, convenient later deployment.

Implementation approach

With the help of two plugins:

  • Inquirer: Terminal interaction
  • Ssh2-sftp-client: transfers files to the server

Step 1: make a package step 2: select the environment you want to deploy on the terminal step 3: upload to the server

The source code

deploy.sh

echo "Packing"
npm run build
node ./deploy/ssh.js
Copy the code

Combining the two commands in a script file also makes it easier to call them later in package.json

helper.js

const inquirer = require('inquirer')
new inquirer.Separator() 
const selectTip = 'project name:'
const options = [
  {
    type: 'checkbox'.name: selectTip,
    message: 'To which environment do you want to deploy the project? `.choices: []}]// Displays a selection prompt window
function showHelper (config) {
  return new Promise((resolve, reject) = > {
    initHelper(config) // Initialize the helper
    inquirer.prompt(options).then(answers= > {
      resolve({ value: findInfoByName(config, answers[selectTip]) }) // Find the selected configuration item
    }).catch((err) = > {
      reject(console.error('Helper display or selection error! ', err))
    })
  })
}

// Initialize the helper
function initHelper (config) {

  for (let item of config) {
    options[0].choices.push(item.name)
  }
  console.log('Checking global configuration... ')
  // Check whether the same name exists
  if (new Set(options[0].choices).size ! == options[0].choices.length) {
    console.error('Please check the configuration information, the same name exists! ')
    process.exit()
  }
}

// Search for the configuration items that meet the requirements
function findInfoByName (config, nameArr) {
  const arrInfo = []
  for (let item of config) {
    for(let name of nameArr) {
      if(item.name === name) {
        arrInfo.push(item)
      }
    }
  }
  return arrInfo
}

module.exports = showHelper
Copy the code

Helper.js mainly implements terminal interaction, confirming the environment you want to deploy

ssh.js

const Client = require('ssh2-sftp-client')

const helper = require ('./helper')
const config = [
  {
    name: 'Development Environment'.enviroment: 'development'.ssh: {
      host: '192.168.0.0'.port: 22.username: 'root'.password: '123',},romotePath: '/root/dev'.// Remote address
    localPath:'./dist'.// Local address
  },
  {
    name: 'Test environment'.enviroment: 'preview'.ssh: {
      host: '192.168.0.0'.port: 22.username: 'root'.password: '123',},romotePath: '/root/pre'.// Remote address
    localPath:'./dist'.// Local address
  },
  {
    name: 'Production environment'.enviroment: 'production'.ssh: {
      host: '192.168.0.0'.port: 22.username: 'root'.password: '123',},romotePath: '/root/prod'.// Remote address
    localPath:'./dist'.// Local address}]function connect(config) {
  const sftp = new Client()
  return sftp
    .connect(config.ssh)
    .then(() = > {
      console.log('Deploying${config.name}`)
      return sftp.uploadDir(config.localPath, config.romotePath)
    }).finally(() = > {
      sftp.end()
    })
}

async function main() {
  const ps = []
  const table = []
  const SELECT_CONFIG = (await helper(config)).value // Configuration information for the selected deployment project
  for(let config of SELECT_CONFIG) {
    table.push({
      enviroment: config.enviroment,
      status: 'OK'
    })
    ps.push(() = > connect(config))
  }
  
  const p = Promise.resolve()
  ps.reduce((p, c) = > {
    return p.then(c)
  }, p).then(() = > {
    console.log('success completed')
    console.table(table);
  }).catch((err) = > {
    console.log(err,'Something's wrong, go and have a look.')
  })
}

main()
Copy the code

All of your configuration information about the environment is written in the config array. Terminal options are also based on the config array. The main method then calls the helper.js method to get the configuration information for the selected deployment environment, and then performs connection uploads one by one using the array’s Reduce method

package.json

"scripts": {
    "deploy": "sh ./deploy/deploy.sh"
}
Copy the code

conclusion

My directory structure



disadvantages

  1. This implementation actually has a security risk, is the service account password is in the project file, so pay attention to not upload the file
  2. Every upload is a file in the server to replace, there is no backup, so can not be rolled back
  3. A lot of JS code is cumbersome and not very elegant

reference

Automatic deployment of front-end Web projects based on Node.js

Github source address

Cross the river and come south from heaven