MENU

一键部署项目到服务器

May 20, 2020 • 浏览量: 972 • 字数: 4263 • 阅读时长: 2分钟 • 前端

相对于部署到 Github Page 来说,可以使用 GitHub Actions 来进行自动部署。我们自己拥有服务器的选手,就相对来说比较麻烦。一般的情况就这些:

方法分析
FTPFTP 的速度相对来说确实太慢了,上传东西真的是龟速
SSH通过 SSH 直接连通服务器,大大加快了传输速度。但是还是需要手动操作数据包
宝塔面板直接打开宝塔页面,找到指定的页面,上传文件即可。但是网速较差的情况下打会很慢

之前每次更新项目都得上传半天,很烦人。所以就着手研究怎么部署比较方便快捷。

设想

1.首先需要把我构建的文件夹压缩为 zip 文件。 (archiver)

2.能不能直接把压缩包从本地通过 SSH 上传到服务器。 (node-ssh)

3.上传到服务器以后怎么操作这个压缩包? (执行预留在服务器的 shell 命令)

上手

首先在根目录创建 deploy 文件夹,并创建config.jsindex.js

├─ deploy
│  ├─config.js
│  └─index.js
├─ docs
├─ public

config.js

导出一些配置信息。

module.exports = {
  path: '/xxxxx/xxxxxxx/public.zip', //服务器上这个文件要放在哪里
  host: 'xxx.xxx.xx.xx', // 服务器的host地址
  username: 'xxxxxxx', // SSH用户名
  password: 'xxxxxxxx', // SSH密码
  port: xx //SSH连接的端口
};

index.js

前要

首先我们需要安装依赖插件

npm install archiver node-ssh -S

依赖安装完成后,导入我们需要的包

const path = require('path');
const archiver = require('archiver');
const fs = require('fs');
const { NodeSSH } = require('node-ssh');
const ssh = new NodeSSH();
const configs = require('./config');

const srcPath = path.resolve(__dirname, '../public');
// 为什么是"../public"?
// 因为我的项目设置的打包名称为public,而且从上面的目录树中可以了解到,public与deploy是一级。
// 所以我为了找到public文件夹,就得使用 "../public"

压缩目录为 public.zip

console.log('开始压缩dist目录...');
startZip();

function startZip() {
  var archive = archiver('zip', {
    zlib: {
      level: 8 // 搜索路径深度
    }
  }).on('error', function (err) {
    throw err; //压缩过程中如果有错误则抛出
  });
  var output = fs.createWriteStream(__dirname + '/public.zip').on('close', function (err) {
    /*压缩结束时会触发close事件,然后才能开始上传,
              否则会上传一个内容不全且无法使用的zip包*/
    if (err) {
      console.log('关闭archiver异常:', err);
      return;
    }
    console.log('已生成zip包');
    console.log('开始上传public.zip至远程机器...');
    uploadFile();
  });

  archive.pipe(output); //典型的node流用法
  archive.directory(srcPath, '/public'); //将srcPach路径对应的内容添加到zip包中/public路径
  archive.finalize();
}

上传文件到服务器

function uploadFile() {
  ssh
    .connect({
      host: configs.host,
      username: configs.username,
      password: configs.password,
      port: configs.port
    })
    .then(function () {
      console.log(configs.path);
      //上传网站的发布包至configs中配置的远程服务器的指定地址
      ssh
        .putFile(__dirname + '/public.zip', configs.path)
        .then(function (status) {
          console.log('上传文件成功');
          console.log('开始执行远端脚本');
          startRemoteShell(); //上传成功后触发远端脚本
        })
        .catch((err) => {
          console.log('文件传输异常:', err);
          process.exit(0);
        });
    })
    .catch((err) => {
      console.log('ssh连接失败:', err);
      process.exit(0);
    });
}

执行远端部署脚本

function startRemoteShell() {
  // 在服务器上cwd配置的路径下执行sh deploy.sh脚本来实现发布
  ssh
    .execCommand('sh deploy.sh', {
      cwd: '/www/wwwroot/reinness.com'
    })
    .then(function (result) {
      console.log('远程STDOUT输出: ' + result.stdout);
      console.log('远程STDERR输出: ' + result.stderr);
      if (!result.stderr) {
        console.log('发布成功!');
        removeLocalFile();
        process.exit(0);
      }
    });
}

为了不占用本地空间,完成操作后删除本地的打包文件

function removeLocalFile() {
  fs.unlink(__dirname + '/public.zip', function (error) {
    if (error) {
      console.log(error);
      return false;
    }
    console.log('删除文件成功');
  });
}

deploy.sh

以我的项目为例,服务器上面的目录结构如下

├─ public
│
└─ deploy.sh

我的站点根节点为 public ,当上传了 public.zip 后,我需要先删除原来的 public 文件夹再解压。然后删除 public.zip。

rm -rf public
unzip public.zip
rm -rf public.zip

在 package.json 中添加 scripts 命令

{
    "scripts": {
        "deploy": "node ./deploy/index.js",  // 一键发布
        "auto": "vuepress build docs && node ./deploy/index.js"  // 一键打包加发布
     }
}

以上所有内容供大家参考,如有问题请及时指正。

Archives QR Code Tip
QR Code for this page
Tipping QR Code
Leave a Comment