前端项目中创建自动化部署脚本,用于 Jenkins 触发 npm run publish 来完成远程部署

核心步骤包括:

  1. 读取 server.config.json 配置,获取目标服务器信息
  2. 使用 scp 上传前端打包文件serverWebPath
  3. 使用 ssh 远程执行部署命令 (例如 pm2 restartnginx reload

1. 安装依赖

使用 Node.js 编写 deploy.js 脚本,需要用到 ssh2fs

npm install ssh2 fs-extra dotenv

2. 在config下配置server.config.json文件

javascript 复制代码
{
  "deploy": {
    "host": "10.2...",
    "port": 36000,
    "username": "root",
    "password": "*#00000",
    "serverWebPath": "/...",
    "splitIncludes": ["models"],
    "splitUpload": false
  },
  "sandbox": {
    "host": "10.2...",
    "port": 36000,
    "username": "root",
    "password": "*#00000",
    "serverWebPath": "/...",
    "splitIncludes": [],
    "splitUpload": true
  }
}

3. deploy.js 自动化脚本

项目根目录 创建 scripts/deploy.js,用于 自动化部署

javascript 复制代码
const fs = require("fs-extra");
const path = require("path");
const { Client } = require("ssh2");

// 读取 server.config.json
const configPath = path.resolve(__dirname, "../server.config.json");
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));

// 选择环境(deploy 或 sandbox)
const env = process.env.ENV || "deploy";
const serverConfig = config[env];

if (!serverConfig) {
  console.error(`配置错误: 未找到环境 ${env} 的配置信息`);
  process.exit(1);
}

// 获取配置信息
const { host, port, username, password, serverWebPath } = serverConfig;
const localBuildPath = path.resolve(__dirname, "../dist"); // 前端打包目录

// 部署逻辑
async function deploy() {
  console.log(`开始部署到 ${env} 环境: ${host}:${port}`);

  const conn = new Client();
  conn
    .on("ready", () => {
      console.log(`连接成功: ${host}`);

      // 上传文件
      uploadFiles(conn)
        .then(() => executeRemoteCommand(conn, `cd ${serverWebPath} && ls -la`))
        .then(() => {
          console.log("部署完成!");
          conn.end();
        })
        .catch((err) => {
          console.error(`部署失败: ${err.message}`);
          conn.end();
        });
    })
    .connect({ host, port, username, password });
}

// 远程执行命令
function executeRemoteCommand(conn, command) {
  return new Promise((resolve, reject) => {
    conn.exec(command, (err, stream) => {
      if (err) return reject(err);
      stream
        .on("close", (code, signal) => resolve(code))
        .on("data", (data) => console.log(`远程输出: ${data.toString()}`))
        .stderr.on("data", (data) => console.error(` 错误: ${data.toString()}`));
    });
  });
}

// 上传文件
function uploadFiles(conn) {
  return new Promise((resolve, reject) => {
    conn.sftp((err, sftp) => {
      if (err) return reject(err);
      sftp.mkdir(serverWebPath, (err) => {
        if (err && err.code !== 4) return reject(err); // 目录已存在则忽略错误
        sftp.fastPut(
          path.join(localBuildPath, "index.html"),
          `${serverWebPath}/index.html`,
          (err) => (err ? reject(err) : resolve())
        );
      });
    });
  });
}

// 执行部署
deploy();

4. 在 package.json 添加 publish 命令

javascript 复制代码
"scripts": {
  "build": "vite build",
  "publish": "npm run build && node scripts/deploy.js"
}
相关推荐
F_Director3 分钟前
简说Vue3 computed原理
前端·vue.js·面试
行走的陀螺仪12 分钟前
Flutter 开发环境配置教程
android·前端·flutter·ios
焦糖小布丁14 分钟前
代码签名证书如何有效消除Windows系统警告?
前端
icebreaker25 分钟前
重新思考 weapp-tailwindcss 的未来
前端·javascript·css
焦糖小布丁28 分钟前
为什么IP地址SSL证书比域名证书更贵?
前端
光影少年32 分钟前
WEBNN是什么,对前端工程带来哪些优势
前端·web3·web
djk888833 分钟前
极简后台框架
前端·css·css3
LilySesy44 分钟前
ABAP+如果在join的时候需要表1的字段某几位等于表2的字段的某几位,需要怎么做?
服务器·前端·数据库·sap·abap·alv
研究司马懿1 小时前
【ETCD】ETCD集群部署(TLS)
数据库·chrome·云原生·自动化·运维开发·etcd
吃饺子不吃馅1 小时前
⚡️ Zustand 撤销重做利器:Zundo 实现原理深度解析
前端·javascript·github