公司有些项目环境没有接入 jenkins 所以部署起来比较麻烦,所以写个脚本节约部署时间。
背景
前端项目分开发、测试、生产环境,开发及测试已接入 jenkins 自动部署,生产环境依然还是手动。每次都需要进行本地打包, 手动压缩上传到服务器目录,ssh 登录服务器后备份旧文件, 手动删除文件再将包解压到指定目录,操作流程比较繁琐,需要提前了解服务器部署目录,不太友好,所以就写了个脚本简化部署操作。
依赖安装
部署包含压缩文件、ssh 登录、文件上传等几个步骤,所以需要安装如下依赖:
- archiver,压缩文件使用。
- node-ssh,ssh 操作。
- silly-datetime,时间处理。
关键代码
在项目根目录新建 deploy.js 脚本,作用是上传压缩包至服务器、备份旧文件,解压代码压缩包。
const fs = require('fs');
const path = require('path');
const archiver = require('archiver');
const { NodeSSH } = require('node-ssh');
const sd = require('silly-datetime');
let args = process.argv.splice(2),
isRollback = args.includes('rollback');
// 当前时间
let curTime = sd.format(new Date(), 'YYYYMMDDHH');
// 当前时间格式化
console.log((isRollback ? '回滚' : '部署') + '时间:' + curTime);
// 设置本地 dist 文件路径
const distPath = path.resolve(__dirname, 'dist');
const ssh = new NodeSSH();
// 远程服务器配置信息
const config = require('./config');
// 本地文件上传至远程服务器
function uploadFile() {
ssh
.connect({
host: config.host,
username: config.username,
password: config.password,
port: 22,
})
.then(() => {
console.log('SSH login success');
ssh
.putFile(
`${__dirname}/dist${curTime}.zip`,
`${config.pathUrl}/dist${curTime}.zip`
)
.then(() => {
console.log('The zip file is upload successful');
remoteFileUpdate();
})
.catch((err) => {
console.log('the file upload fail:', err);
process.exit(0);
});
})
.catch((err) => {
console.log('SSH conneting fail:', err);
process.exit(0);
});
}
// 远端文件更新
const remoteFileUpdate = () => {
let cmd = isRollback
? `rm dist && mv dist.bak${curTime} dist`
: `mv dist dist.bak${curTime} && unzip dist${curTime}.zip`;
ssh
.execCommand(cmd, {
cwd: config.pathUrl,
})
.then((result) => {
console.log(`The update message is: ${result.stdout}`);
if (!result.stderr) {
console.log('Gratefule! update success!');
process.exit(0);
} else {
console.log('Something wrong:', result);
process.exit(0);
}
});
};
// 本地文件压缩
const zipDirector = () => {
const output = fs.createWriteStream(`${__dirname}/dist${curTime}.zip`);
const archive = archiver('zip', {
zlib: { level: 9 },
}).on('error', (err) => {
throw err;
});
output.on('close', (err) => {
if (err) {
console.log('something error width the zip process:', err);
return;
}
uploadFile();
console.log(`${archive.pointer()} total bytes`);
console.log(
'archiver has been finalized and the output file descriptor has closed.'
);
});
output.on('end', () => {
console.log('Data has been drained');
});
archive.pipe(output);
archive.directory(distPath, '/dist');
archive.finalize();
};
// 回滚代码
if (isRollback) {
remoteFileUpdate();
} else {
// 更新代码
zipDirector();
}
服务器上的备份,解压等操作是通过执行 shell 命令做的,你也可以自己预先写好相关脚本去执行。
使用方法
在根目录新建一个 config.js
用于存放服务器 IP、用户名、密码、部署目录等信息,然后就可以在 package.json 中追加命令去调用上面的 node 脚本。
"scripts": {
"deploy": "node deploy.js",
"rollback": "node deploy.js rollback"
}
执行命令执行相应操作:
-
npm run deploy
,部署 + 备份。 -
npm run rollback
,回滚代码。