前端项目中创建自动化部署脚本,用于 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"
}
相关推荐
程序员爱钓鱼27 分钟前
Rust String 与 &str 详解:字符串所有权、借用与转换
前端·后端·rust
AlanBruce28 分钟前
从串口仪表到西门子PLC:摩尔信使MThings的多协议设备接入能力
自动化·plc·modbus·mthings·摩尔信使·西门子s7
码农学院32 分钟前
GEO与SEO协同:从传统搜索到生成式搜索的平滑迁移路径
服务器·前端·python
咩咩啃树皮9 小时前
第40篇:Vue3组件化开发精讲——组件拆分、复用、父子通信、工程化架构
java·前端·架构
阳光是sunny9 小时前
LangGraph中的Reducer是什么
前端·人工智能·后端
触底反弹9 小时前
一文搞懂 Tailwind CSS 弹性布局:从原理到实战
前端·css·html
阳光是sunny9 小时前
从链到图:LangGraph 入门基础全解析
前端·人工智能·后端
小林ixn10 小时前
从 ??= 到 onKeyDown:一个 React 组件的“自我修养”
前端·javascript·react.js
REDcker10 小时前
显示分辨率标准对照详解
前端·网络·分辨率·显示·屏幕
এ慕ོ冬℘゜11 小时前
前端实战:jQuery 多条件联合搜索(标题模糊查询 + 日历时间段筛选)
前端·javascript·jquery