This is the fourth day of my participation in the August Text Challenge.More challenges in August

preface

The traditional deployment process requires at least two steps: 1. NPM run build → Generate the package file in the dist folder 2. Use winscp and XFTP to upload the package file to the specified directory on the server

This does not include the need for code update submission to be released again. If only one system is developed independently, the frequency of deployment is relatively low and the efficiency is acceptable

If there are multiple systems running in parallel at the same time, the daily release needs to be carried out, and the repeated workload and operational errors will bring a very unpleasant feeling.

For the front end, is there a more automated deployment process?

When it comes to automated deployment, we will think of Jenkins. It is difficult to deploy Jenkins for beginners. Today, I will give you a transition plan.

This tutorial is a Vue project, using SCp2 to automatically deploy to static files, using cross-env to set up and use environment variables, set up production environment or development environment.

Configuration files involved:

  1. /deploy/* to compile the deployment code
  2. .env.*, project environment Settings file, packaging to distinguish the development environment, production environment.
  3. The script module in package.json configures the execution command

The installation

1. Install SCP2: a pure JavaScript secure copy program based on SSH2. It’s written in pure JavaScript and runs on every OS, even Windows. You must use Nodejs (V0.8.7 or later) for it to work properly.

2. Install cross-env: This is a script that runs cross-platform Settings and uses environment variables. NODE_ENV=production Most Windows command prompts block when setting environment variables like this.

npm i --save-dev scp2 cross-env
Copy the code

Configure the test environment or formal environment

  1. In the project root directory, create the.env.dev file (test environment variables)
  • VUE_APP_SERVER_ID Indicates that the ID of the test server to be deployed is 1
  • VUE_APP_CURRENTMODE: indicates the current test environment
  • NODE_ENV = production NODE_ENV = production NODE_ENV = production NODE_ENV = production NODE_ENV = production
NODE_ENV = production VUE_APP_CURRENTMODE = development VUE_APP_SERVER_ID = 1Copy the code
  1. In the project root directory, create the.env.prod file (production environment variables)
  • VUE_APP_SERVER_ID Indicates that the ID of the official server to be deployed is 0
  • VUE_APP_CURRENTMODE: indicates the current official environment
Prod NODE_ENV = production VUE_APP_CURRENTMODE = production VUE_APP_SERVER_ID = 0Copy the code

Configure the SSH remote login account for the server

In the root directory, create the deploy/products.js file and write the server account

/* * Read the env environment variable */
const fs = require('fs');
const path = require('path');

// env specifies the server ID for the packaging environment
const envfile = process.env.VUE_APP_CURRENTMODE === 'prod' ? '.. /.env.prod' : '.. /.env.dev';

// env Specifies the path of the environment variable
const envPath = path.resolve(__dirname, envfile);

/ / env object
const envObj = parse(fs.readFileSync(envPath, 'utf8'));
const SERVER_ID = parseInt(envObj['VUE_APP_SERVER_ID']);

function parse(src) {
  // parse the file with KEY=VAL
  const res = {};
  src.split('\n').forEach(line= > {
    // matching "KEY' and 'VAL' in 'KEY=VAL'
    // eslint-disable-next-line no-useless-escape
    const keyValueArr = line.match(/^\s*([\w.-]+)\s*=\s*(.*)? \s*$/);
    // matched?
    if(keyValueArr ! =null) {
      const key = keyValueArr[1];
      let value = keyValueArr[2] | |' ';

      // expand newlines in quoted values
      const len = value ? value.length : 0;
      if (len > 0 && value.charAt(0) = = ='"' && value.charAt(len - 1) = = ='"') {
        value = value.replace(/\n/gm.'\n');
      }

      // remove any surrounding quotes and extra spaces
      value = value.replace(/(^['"]|['"]$)/g.' ').trim(); res[key] = value; }});return res;
}

/* * Define multiple server accounts and export the current environment server account */ based on the SERVER_ID
const SERVER_LIST = [
  {
    id: 0.name: 'A- Formal environment '."host": '* * * * * *'./ / IP address
    "port": '80'.// Server port
    "username": 'root'./ / user name
    "password": '* * * * * * *'./ / password
    "path": '/home/project/landingpage/'  , // Server project directory
    'localfile':envObj.VUE_APP_DEV   // Local package file name
  },
  {
    id: 1.name: 'A- Production environment '."host": '* * * * * *'./ / IP address
    "port": '2205'.// Server port
    "username": 'root'./ / user name
    "password": '* * * * * *'./ / password
    "path": '/home/project/demo/' ,  // Server project directory
    'localfile':envObj.VUE_APP_DEV   // Local package file name},];module.exports = SERVER_LIST[SERVER_ID];
  
Copy the code

Compile automatic deployment scripts

In the project root directory, create the deploy/index.js file.

  1. Delete the files before the server. Prevent excessive redundant files caused by continuous uploading.
  2. Upload the new file to the server and replace it with the original folder.

Fault: If the file is too large, the upload time is too long. The server will be unavailable for a period of time.

const scpClient = require('scp2'); const ora = require('ora'); const chalk = require('chalk'); const server = require('./products'); Const spinner = ora(' publishing to '+ (process.env.vue_app_currentmode === 'prod'? 'Production' : 'test ') +' server... '); var Client = require('ssh2').Client; var conn = new Client(); Conn. on('ready', function() {// rm delete dist, Nginx conn.exec('rm -rf '+server.path+' ndocker restart nginx', function(err, stream ) { if (err) throw err; Stream. on('close', function(code, signal) {// After executing shell command, put the start upload deployment project code in this spinner. scpClient.scp( server.localfile, { host: server.host, // port: server.port, username: server.username, password: server.password, path: server.path }, function(err) { spinner.stop(); If (err) {console.log(chalk. Red (' failed to publish.\n')); throw err; } else { console.log( chalk.green( 'Success! Successfully published to '+ (process.env.node_env === 'prod'? 'Production' : 'test ') +' server! \n' ) ); }}); conn.end(); }) .on('data', function(data) { console.log('STDOUT: ' + data); }) .stderr.on('data', function(data) { console.log('STDERR: ' + data); }); }); }) .connect({ host: server.host, // port: server.port, username: server.username, password: server.password //privateKey: require('fs').readFileSync('/home/admin/.ssh/id_dsa') });Copy the code

Add package.json to scripts and set the name to “deploy”

Use cross-env to set and use environment variables across platforms. Run the NPM run deploy:dev command to the test environment and NPM run deploy:prod command to the production environment

 "scripts": {
    "serve": "vue-cli-service serve  --open ",
    "app": "npm run serve && npm run node",
    "build": "vue-cli-service build",
    "node": "node ./server/app.js",
    "deploy:dev": "npm run build && cross-env VUE_APP_CURRENTMODE=dev node ./deploy",
    "deploy:prod": "npm run build && cross-env VUE_APP_CURRENTMODE=prod node ./deploy",
    "test:unit": "vue-cli-service test:unit"
  },
Copy the code

Six optimized version of automatic deployment script compilation: in order to solve the uploading process of the server can not open the problem

  1. Install the Compressing plug-in first and compress the package folder.

    npm i compressing --save-dev
    Copy the code
  2. Then upload the compressed file to the server.

  3. Finally, link to the server, delete the original file, and decompress the latest uploaded file.

const scpClient = require('scp2'); const chalk = require('chalk'); const server = require('./products'); const Client = require('ssh2').Client; const ora = require('ora'); var compressing = require("compressing"); Const environment = server.path+server. localPath const spinner = ora(' releasing to '+ environment +' server... '); Const ziping = ora(' ziping '+ environment); const conn = new Client(); / / compression ziping. Start () compressing.zip.com pressDir (for server localpath + "/", "dist.zip") .then((e) => { ziping.stop() console.log(chalk.green('Success! Compression succeeded ')); spinner.start() scpClient.scp( 'dist.zip', { host: server.host, // port: server.port, username: server.username, password: server.password, path: server.path }, (err) => { spinner.stop(); If (err) {console.log(chalk. Red (' failed to publish.\n')); throw err; } else { conn.on('ready', () => { conn.exec('sudo unzip -o '+server.path+'dist.zip\ndocker restart nginx', (err, stream) => { if (err) throw err; stream .on('close', function(code, signal) { console.log(chalk.green('Success! Successfully published to '+ environment +' server! \n')); conn.end() }) }) }).connect({ host: server.host, // port: server.port, username: server.username, password: server.password //privateKey: require('fs').readFileSync('/home/admin/.ssh/id_dsa') }); }}); }) .catch(err => { console.log(chalk.red('Fail! Compression failed ')); });Copy the code