前端專案nodejs自動部署指令碼

hjavn 發表於 2021-09-23
前端 Node.js

工具與資源中心

幫助開發者更加高效的工作,提供圍繞開發者全生命週期的工具與資源

developer.aliyun.com/tool/?spm=a1z...

背景

前端專案分開發、測試、生產環境,開發及測試已接入 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,回滾程式碼。

原文連結:developer.aliyun.com/article/79188...

本作品採用《CC 協議》,轉載必須註明作者和本文連結