Node.js 静态资源打包上传脚本

编辑于2018年09月18日

在实际工作中,经常需要将构建好的静态资源上传到服务器的指定目录中。之前一直都是手动完成此操作,效率实在不高。近期,使用 Node.js 编写了一个简单地脚本,用来完成此工作。全部的代码我已上传到 gist

人工操作

在没有写脚本之前,这些步骤都是人工操作,大致的步骤如下:

  1. 执行 npm run build 进行项目构建。
  2. 将打包生成的静态资源压缩成 zip 包。
  3. 使用 scp 将压缩包上传到服务器中。
  4. SSH 连接服务器在服务器上完成解压工作。

或者,如果只是修改部分文件,我也会使用 sshfs 将服务器目录挂载到本地,然后进行修改。

脚本实现

脚本即是将上面的人工操作该为代码实现,主要需要解决以下几个问题:

  1. 服务器的 ip 和登录密码是不固定,需要能通过参数读取。
  2. 需要使用 Node.js 打包静态资源并上传服务器。
  3. 如何在服务器上执行解压命令?

参数读取

Node.js 脚本如何读取命令行参数可以参考阮老师的博客,我使用的是 yargs 模块。

const argv = require('yargs').argv;

const host = argv.h || '192.168.1.188';// 读取主机 ip,默认是 192.168.1.188
const password = argv.p || '';// 主机密码 SSH 密码

因为这个项目中文件路径、服务器用户名等都是固定的,所有就没有支持参数填写的方式。

打包并上传

文件打包可以通过 child_process 模块新建子进程,执行系统的 zip 命令。

const util = require('util');
const exec = util.promisify(require('child_process').exec);

...

console.log('[2/4] 打包静态资源,生成 zip 包...');
  result = await exec(`cd dist && zip -r ${ARCHIVE_NAME} ./*`);
  console.log(result.stdout);

静态资源打包好以后,需要上传到服务器中,我这里使用是 scp2。原本我打算像打包一下,使用系统的 scp 命令,但是我没有配置 SSH 免密登录,需要在 scp 时指定服务器密码,而 scp2 能很好地解决此问题。

const scpClient = require('scp2');

...
 
function scp() {
  return new Promise((resolve, reject) => {
    scpClient.scp(`dist/${ARCHIVE_NAME}`, {
      host,
      username: USER,
      password: password,
      path: REMOTE_PATH,
    }, function(err) {
      if (err) {
        reject(err);
      } else {
        resolve();
      }
    });
  });
}

服务器上解压

静态资源包上传完毕之后,我们需要在服务器上完成解压,这里就需要能在服务器上远程执行命令。我使用了 simple-ssh 来完成此工作。它可以为我们建立一个与服务器之间的 SSH 连接,然后链式的在服务器上执行命令。

const scpClient = require('scp2');

...

function execRemoteOperations() {
  return new Promise((resolve, reject) => {
    const ssh = new SSH({
      host,
      user: USER,
      pass: password,
    });

    ssh
        .exec(`unzip -o -d ${REMOTE_PATH} ${REMOTE_PATH}/${ARCHIVE_NAME}`, {
          out: (stdout) => console.log(stdout),
        })
        .exec(`rm ${REMOTE_PATH}/${ARCHIVE_NAME}`, {
          out: (stdout) => console.log(stdout),
          exit: () => {
            resolve();
          },
        })
        .on('error', function(err) {
          ssh.end();
          reject(err);
        })
        .start();
  });
}

上述代码主要完成服务器上解压,并在解压完成后删除压缩包操作。

总结

使用脚本减少了很多的工作量,以前需要一步步手动操作,现在只用在命令行敲一个命令即可。
原本是打算写一个 Shell 脚本的,不过并不是特别属性,尤其是没有配置 ssh 免密登录,不太清楚如何处理输入密码这类交互情况。我知道 expect 可以实现,但是不了解如何使用,所以就放弃了。不过,后面我还是会尝试使用 expect 编写一个。