自动化部署核心SSH: 主要是通过node-ssh 进行 SSH 连接并执行命令,上传文件夹,完成部署工作
// 引入对应模块
import { execSync } from "child_process";
import fs from "fs";
import path from "path";
import inquirer from "inquirer";
import { NodeSSH } from "node-ssh";
import Client from "ssh2-sftp-client";
const __dirname = path.resolve();
// 配置信息
let serverHost = ""; // 服务器ip地址
const serverUser = "root";
const localDistPath = path.join(__dirname, ""); // 打包后的文件夹路径
const remoteDistPath = ""; // 服务器上的目标路径
let password = "";// 服务器秘密
// 编辑器里交互方法 使用 inquirer
inquirer
.prompt([
{
type: "list",
message: "请选择需要操作的服务环境",
name: "environment",
choices: ["测试", "生产"],
},
])
.then(({ environment }) => {
if (environment === "生产") { //生产需要更换默认服务器信息
serverHost = "";
password = "";
}
executeRemoteCommand();
});
// 开始上传包
async function pushDist() {
try {
const exists = fs.existsSync(localDistPath);
if (!exists) {
return console.log("dist文件夹不存在,请确保已经打包完毕!! ");
}
const sftp = new Client();
try {
await sftp.connect({
host: serverHost,
username: serverUser,
password,
});
// 上传dist目录
console.log(`文件上传中,请稍等~`);
await sftp.uploadDir(localDistPath, remoteDistPath);
// 递归遍历文件夹进行文件上传
console.log(`文件已上传到 ${remoteDistPath}`);
} catch (err) {
console.error("文件上传失败:", err);
} finally {
await sftp.end();
}
} catch (err) {
console.log("文件上传失败", err);
}
}
// 删除文件
async function executeRemoteCommand() {
let filePath = ""; //同remoteDistPath一样
// node-ssh 不支持文件上传功能,它主要是一个 SSH 客户端库,用于执行远程命令
const ssh = new NodeSSH();
try {
// 连接到远程服务器
await ssh.connect({
host: serverHost,
username: serverUser,
password, // 或者使用privateKey等其他认证方式
});
// 执行远程命令
await ssh.execCommand(`rm -rf ${filePath}`);
console.log(`文件 ${filePath} 已从远程服务器成功删除。开始上传dist包`);
pushDist();
} catch (error) {
console.error(`删除文件 ${filePath} 失败:`, error);
} finally {
// 断开连接并释放资源
ssh.dispose();
}
}
// 递归上传文件
async function uploadDirectory(sftp, localDir, remoteDir) {
// 读取本地目录中的所有文件和子目录
const files = await fs.promises.readdir(localDir, { withFileTypes: true });
// 遍历文件和子目录
for (const file of files) {
const localFilePath = path.join(localDir, file.name);
const remoteFilePath = path.join(remoteDir, file.name);
// 如果是文件,则上传
if (file.isFile()) {
try {
await sftp.mkdir(remoteDir, true);
await sftp.put(localFilePath, remoteFilePath);
console.log(`上传文件: ${localFilePath} -> ${remoteFilePath}`);
} catch (err) {
console.error(`上传文件失败: ${localFilePath} -> ${remoteFilePath}`, err);
}
} else if (file.isDirectory()) { // 如果是目录,则递归上传
try {
// 确保远程目录存在
await sftp.mkdir(remoteFilePath, true); // 第二个参数为true时,如果目录已存在则不会报错
console.log(`创建目录: ${remoteFilePath}`);
// 递归调用自身,上传子目录
await uploadDirectory(sftp, localFilePath, remoteFilePath);
} catch (err) {
console.error(`创建目录失败: ${remoteFilePath}`, err);
}
}
}
}