对于没有搭建Jenkins等自动化打包平台来说,平时部署前端项目流程是:先部署到测试环境ok后再发布到生产环境上,部署到测试环境用 xshell 连上服务器,然后用 xftp /winSCP连接服务器,然后本地 build 项目,接着把 build 好的文件通过 xftp/winSCP 上传到服务器上,整个流程感觉稍有繁琐,重复。
我们可以利用scp2自动化部署到静态文件服务器,从而实现自动化部署前端项目!
1、安装scp2
scp2是一个基于ssh2增强实现,纯粹使用JavaScript编写。
而ssh2就是一个使用nodejs对于SSH2的模拟实现。scp是Linux系统下基于SSH登陆进行安全的远程文件拷贝命令。这里我们就用这个功能,在Vue编译构建成功之后,将项目推送至测试/生产环境,以方便测试,提高效率。
安装scp2:npm install scp2 --save-dev
2、配置测试/生产环境 服务器SSH远程登陆基本信息
在项目根目录下新建deploy文件夹,再新建config.js来存放服务器的配置信息:
/**
* 服务器相关配置
*/
const SERVER_LIST = [
{
id: 'test',
name: '测试环境',
host: '80.xxx.xx.xx', // ip
port: 22, // 端口
username: 'root',
password: '******',
path: '/opt/xxx/front' // 项目静态文件存放地址
},
{
id: 'prod',
name: '正式环境',
host: '101.x.xx.xx',
port: 22,
username: 'root',
password: '******',
path: '/opt/xxx/front'
}
];
module.exports = SERVER_LIST;
3、使用scp2库,创建自动化部署脚本
const scpClient = require('scp2');
const ora = require('ora');
const chalk = require('chalk');
const server = require('./config);
const spinner = ora('正在发布到' + (process.env.NODE_ENV === 'prod' ? '生产' : '测试') + '服务器...');
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('发布失败.\n'));
throw err;
} else {
console.log(chalk.green('Success! 成功发布到' + (process.env.NODE_ENV === 'prod' ? '生产' : '测试') + '服务器! \n'));
}
}
);
通过scp库我们就能把dist文件夹下的所有文件上传到服务器指定路径,从而完成我们项目的自动化部署。
4、添加 package.json 中的 scripts 命令, 自定义名称为 “deploy”
"scripts": {
"serve": "vue-cli-service serve --mode dev",
"build": "vue-cli-service build --mode prod",
"deploy": "cross-env NODE_ENV=prod node ./deploy"
},
至此,我们直接执行命令npm run deploy就能完成自动化部署。
但是,目前还有几个问题需要解决:
- 怎样区分多环境部署?
- 服务器账号和密码为了保密不想写在配置里怎么办?
- 想备份上一版本的文件怎么办?
4.1 区分多环境部署
-
第一种方法:通过配置不同环境不同的部署命令来区分,比如:npm run deploy:test/npm run deploy:prod,然后通过不同命令的环境变量来读取不同的配置文件。
"deploy:dev": "cross-env NODE_ENV=dev node ./deploy",
"deploy:prod": " cross-env NODE_ENV=prod node ./deploy"
-
第二种方法:通过用户从命令行的输入来获取部署的环境,将在下一点详细讲解。
4.2 服务器账号和密码为了保密不想写在配置里怎么办?
为了保密性,这两个信息不会存放在配置文件里,那么我们可以通过node 的readline模块来让用户输入账号和密码。
导入readline模块:
const readline = require('readline');
创建readline实例:
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})
利用readlinde的quetion方法来“提问”,然后接受用户输入的值:
rl.question(‘请输入服务器账号:’, (as) => {
console.log(as);
})
至此,我们就能拿到用户输入的账号了。
现在我们整理一下来获取用户输入的环境、账号、密码:
let server = null;
const questions = ['Please input publish environment(test\\prod\\yanshi): ', 'Please input server username: ', 'Please input server password: ']
const linelimit = 3; // 用户输入的行数
let inputArr = [];
let index = 0;
function runQueLoop() {
if (index == linelimit) {
server = config.find(i => i.id == inputArr[0]) //通过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, 我们拿到了用户输入的环境、服务器账号和密码,我们服务器的配置信息就完整了,并且保证了私密信息的保密性,也提升了与用户的交互。
4.3 如何备份上一版本的文件?
备份文件我首先想到的就是通过使用Linux的命令行还进行文件的操作,大体的思路:
- 进入到静态文件存放的根目录;
- 新建一个备份文件夹(我们可以通过时间戳来命名,也方便回溯版本);
- 将现在正运行版本文件夹下的所有文件拷贝的新建的备份文件夹;
- 文件备份就完成了,然后我们再把我们需要发布的静态文件上传即可!
有了思路过后,我们来使用ssh2库来执行脚本命令,实现我们的思路:
var Client = require('ssh2').Client;
var conn = new Client();
function copyFile() {
let pathArr = server.path.split('/'), rootFolder = pathArr[pathArr.length-1];//获取根文件夹
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) {
// 在执行shell命令后,开始上传部署项目代码
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! 发布失败.\n'));
rl.close();
throw err;
} else {
console.log(chalk.green('Success! 成功发布到' + server.host + '服务器! \n'));
rl.close();
}
}
);
conn.end();
})
});
})
.on('error', function (err) {
console.log(chalk.red('Fail! 服务器连接失败.\n'));
rl.close();
throw err;
})
.connect({
host: server.host,
port: server.port,
username: server.username,
password: server.password
});
}
OK,在这里我们通过配置文件里的path来动态获取根目录和根文件夹,执行备份命令后再进行文件上传! |