使用node编写自动部署静态文件脚本

2,598 阅读2分钟

前端开发总避免不了把写好的代码或者打包好的静态文件部署到服务器
小公司没有专门的运维搞这些
每次都是自己打包好 用ftp连接服务器 然后上传
久而久之就比较烦 就想着怎么用程序解决这些问题
后来发现使用node可以做到一件部署静态文件到服务器
就在这里整理一下 以后用到可以作为参考

下面是代码


安装所需的依赖

ora   // 一个进度条插件 让等待不在无聊的插件
zip-local   // 压缩文件的插件 用来压缩打包好的静态文件
shelljs   // 用来在代码中执行命令行操作
chalk   // 用于控制台带颜色的输出 告别纯白字体
inquirer   // 用于命令行交互 使脚本更灵活
node-ssh   // 用来连接服务器

以上插件都是很好用的插件 可以了解一下 这里只是简单使用 满足需求就行


安装完以后就开始写

先创建一个配置用的文件

// deploy.config.js

module.exports = Object.freeze({
  SERVER_PATH: "", // 服务器ip地址
  SSH_USER: "root", // 服务器用户名
  SSH_KEY: "", // 服务器密码 
  PORT: 22, // 端口 默认为22
  DIST: "./build", // 需要部署的打包过后的文件夹 根据项目不同值不同 一般为 build static 或者dist
  SCRIPT: "npm run build", // 打包命令 可能项目由不同的构建命令 如打包指定环境的代码
  PATH: "/opt/book/admin", // 服务器存放静态文件目录
  COMMONDS: [`ls`, `rm index.html`, `rm -r css/`, `rm -r js/`], // 上传前执行的命令 本例是指 查看服务器对应/opt/book/admin下的文件 然后删除index.html,css,js这写文件和目录,  之后会执行上传本地文件到服务器操作
});

完了开始编写脚本文件

引入依赖和配置文件 然后定义一些便捷函数

//  deploy.js
const fs = require("fs");
const path = require("path");
const ora = require("ora");
const zipper = require("zip-local");
const shell = require("shelljs");
const chalk = require("chalk");
const CONFIG = require(path.resolve(process.cwd(), "./deploy.config.js"));
const inquirer = require("inquirer");
const NodeSSH = require("node-ssh").NodeSSH;
let SSH = new NodeSSH();
const errorLog = (error) => console.log(chalk.red(`---------------> ${error}`));
const defaultLog = (log) => console.log(chalk.blue(`---------------> ${log}`));
const successLog = (log) => console.log(chalk.green(`---------------> ${log}`));
// 文件夹位置
const distDir = path.resolve(process.cwd(), CONFIG.DIST||'./dist');
const distZipPath = path.resolve(process.cwd(), "./dist.zip");


编写功能函数

// 打包 npm run build
const compileDist = async () => {
  // 进入本地文件夹
  shell.cd(path.resolve(process.cwd(), "./"));
  shell.exec(CONFIG.SCRIPT||'npm run build');
  successLog("编译完成");
};

// ********* 压缩dist 文件夹 *********
const zipDist = async () => {
  try {
    if (fs.existsSync(distZipPath)) {
      defaultLog("dist.zip已经存在, 即将删除压缩包");
      fs.unlinkSync(distZipPath);
    } else {
      defaultLog("即将开始压缩zip文件");
    }
    await zipper.sync.zip(distDir).compress().save(distZipPath);
    successLog("文件夹压缩成功");
  } catch (error) {
    errorLog(error);
    errorLog("压缩dist文件夹失败");
  }
};

// ********* 执行清空线上文件夹指令 *********
const runCommond = async (commond) => {
  const result = await SSH.exec(commond, [], { cwd: CONFIG.PATH });

  console.log(chalk.yellow(result));
};
const COMMONDS = CONFIG.COMMONDS || [];
// ********* 执行清空线上文件夹指令 *********
const runBeforeCommand = async () => {
  defaultLog("执行前置命令");
  for (let i = 0; i < COMMONDS.length; i++) {
    await runCommond(COMMONDS[i]);
  }
};

// ********* 通过ssh 上传文件到服务器 *********
const uploadZipBySSH = async () => {
  // 上传文件
  let spinner = ora("准备上传文件").start();
  try {
    await SSH.putFile(distZipPath, CONFIG.PATH + "/dist.zip");
    successLog("完成上传");
    spinner.text = "完成上传, 开始解压";
    await runCommond("unzip -o ./dist.zip");
    spinner.stop();
    successLog("部署完成");
    process.exit(0);
  } catch (error) {
    errorLog(error);
    errorLog("上传失败");
  }
  spinner.stop();
};

// ********* 连接ssh *********
const connectSSh = async () => {
  defaultLog(`尝试连接服务: ${CONFIG.SERVER_PATH}`);
  let spinner = ora("正在连接");
  spinner.start();
  try {
    spinner.stop();
    SSH.connect({
      host: CONFIG.SERVER_PATH,
      username: CONFIG.SSH_USER,
      password: CONFIG.SSH_KEY,
      port: CONFIG.PORT || 22,
    }).then(async () => {
      await runBeforeCommand();
      await uploadZipBySSH();
    });
    successLog("SSH 连接成功");
  } catch (error) {
    errorLog(error);
    errorLog("SSH 连接失败");
  }
};

最后写一下交互的东西就可以执行命令了

// 执行打包上传命令
async function runTask(hasBuild) {
  if (hasBuild) {
    await compileDist();
  }
  await zipDist();
  await connectSSh();
}

console.log(CONFIG);

// defaultLog('服务器配置检查')
inquirer
  .prompt([
    {
      type: "confirm",
      name: "hasBuild",
      message: "是否需要打包",
    },
  ])
  .then((answers) => {
    let hasBuild = answers.hasBuild
      ? true //需要打包直接打包
      : fs.existsSync(distZipPath) // 不需要打包 判断是否有dist.zip 没有的话重新打包
        ? false
        : true
    runTask(hasBuild);
  });

把自动部署脚本添加到package.json中

"scripts": {
    ...
    "dpl": "node deploy/index.js",
    ...
  },

到这里就基本结束了
下面是我这边的运行效果

执行脚本 执行脚本 检查配置 检查配置 打包压缩完成 进行上传和解压