For the lack of Jenkins and other automatic packaging platforms, the usual process of deploying front-end projects is: first deploy to the test environment ok, then publish to the production environment, then deploy to the test environment, connect to the server with xshell, then connect to the server with xftp/winSCP, then build the local project, and then pass the built files through xftp/winSCP Upload to the server, the whole process feels a little cumbersome and repetitive.
We can use scp2 to automatically deploy to the static file server, so as to automatically deploy the front-end project!
1. Install scp2
scp2 is an enhanced implementation based on SSH 2, written purely in JavaScript.
SSH2 is a simulation implementation of SSH2 using nodejs. scp is a secure remote file copy command based on SSH login in Linux system. Here we use this function to push the project to the test / production environment after the Vue compilation and construction are successful, so as to facilitate testing and improve efficiency.
To install scp2:
npm install scp2 --save-dev
2. Configuration test / production environment server SSH Remote Login basic information
Create a new deploy folder in the root directory of the project, and then create config.js to store the configuration information of the server:
/** * Server related configuration */ const SERVER_LIST = [ { id: 'test', name: 'testing environment', host: '80.xxx.xx.xx', // ip port: 22, // port username: 'root', password: '******', path: '/opt/xxx/front' // Project static file storage address }, { id: 'prod', name: 'Formal environment', host: '101.x.xx.xx', port: 22, username: 'root', password: '******', path: '/opt/xxx/front' } ]; module.exports = SERVER_LIST;
3. Use scp2 library to create automatic deployment script
const scpClient = require('scp2'); const ora = require('ora'); const chalk = require('chalk'); const server = require('./config); const spinner = ora('Publishing to' + (process.env.NODE_ENV === 'prod' ? 'production' : 'test') + 'The server...'); spinner.start(); scpClient.scp( 'dist/', { 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('Publishing failure.\n')); throw err; } else { console.log(chalk.green('Success! Successfully published to' + (process.env.NODE_ENV === 'prod' ? 'production' : 'test') + 'The server! \n')); } } );
Through the scp library, we can upload all files under the dist folder to the designated path of the server, so as to complete the automatic deployment of our project.
4. Add the scripts command in package.json with the custom name of "deploy"
"scripts": { "serve": "vue-cli-service serve --mode dev", "build": "vue-cli-service build --mode prod", "deploy": "cross-env NODE_ENV=prod node ./deploy" },
At this point, we can directly execute the command npm run deploy to complete the automatic deployment.
However, there are still several problems to be solved:
- How to distinguish multi environment deployment?
- What if the server account and password are not written in the configuration for confidentiality?
- What to do if you want to back up the previous version of the file?
4.1 differentiate multi environment deployment
-
The first method is to distinguish by configuring different deployment commands in different environments, such as npm run deploy:test/npm run deploy:prod, and then read different configuration files through the environment variables of different commands.
"deploy:dev": "cross-env NODE_ENV=dev node ./deploy", "deploy:prod": " cross-env NODE_ENV=prod node ./deploy"
-
The second method: obtain the deployed environment through the user's input from the command line, which will be explained in detail in the next point.
4.2 what if the server account and password are not written in the configuration for confidentiality?
For the sake of confidentiality, these two information will not be stored in the configuration file, so we can let the user enter the account and password through the readline module of node.
Import readline module:
const readline = require('readline');
To create a readline instance:
const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
Use readlinde's question method to "ask questions" and then accept the value entered by the user:
rl.question('Please enter the server account:', (as) => { console.log(as); })
At this point, we can get the account entered by the user.
Now let's get the environment, account and password entered by the user:
let server = null; const questions = ['Please input publish environment(test\\prod\\yanshi): ', 'Please input server username: ', 'Please input server password: '] const linelimit = 3; // Number of lines entered by the user let inputArr = []; let index = 0; function runQueLoop() { if (index == linelimit) { server = config.find(i => i.id == inputArr[0]) //Match environment by id server.username = inputArr[1]; server.password = inputArr[2]; copyFile(); return; } rl.question(questions[index], (as) => { inputArr[index] = as; index++; runQueLoop() }) } rl.on('close', () => { process.exit(0) }) runQueLoop()
OK, when we get the environment, server account and password entered by the user, the configuration information of our server will be complete, and the confidentiality of private information will be guaranteed, and the interaction with the user will be improved.
4.3 how to back up the previous version of files?
The first thing I want to do is to use the Linux command line to perform file operations. The general idea is:
- Enter the root directory where the static file is stored;
- Create a new backup folder (we can name it by time stamp, which is also convenient for backtracking version);
- The new backup folder that copies all files under the version folder that are now running;
- File backup is finished, and then we can upload the static file we need to publish!
After thinking about it, we will use the ssh2 library to execute script commands to realize our thinking:
var Client = require('ssh2').Client; var conn = new Client(); function copyFile() { let pathArr = server.path.split('/'), rootFolder = pathArr[pathArr.length-1];//Get root folder pathArr.pop(); let rootPath = pathArr.join('/'); const conn = new Client(); conn.on('ready', function () { conn.exec(`cd ${rootPath}\n mkdir ${rootFolder}${currTime}\n cp -r ${rootFolder} ${rootFolder}${currTime}\n rm -rf ${rootFolder}`, function (err, stream) { if (err) throw err; stream.on('close', function (code, signal) { // After executing the shell command, start to upload the deployment project code spinner.start(); scpClient.scp( './dist', { 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('Fail! Publishing failure.\n')); rl.close(); throw err; } else { console.log(chalk.green('Success! Successfully published to' + server.host + 'The server! \n')); rl.close(); } } ); conn.end(); }) }); }) .on('error', function (err) { console.log(chalk.red('Fail! Server connection failed.\n')); rl.close(); throw err; }) .connect({ host: server.host, port: server.port, username: server.username, password: server.password }); }
OK, here we use the path in the configuration file to dynamically obtain the root directory and root folder, execute the backup command, and then upload the file! |