效能工具之前端自动化部署打包发布上传脚本(五)命令行加载、上传进度功能

问题描述

需求描述:

  • 前端代码写完以后,执行打包命令,npm run build命令会打包出一个dist文件夹
  • 然后再把这个dist文件夹,丢到远程服务器上
  • 然后通过nginx反向代理去给用户使用

这个环节不同公司的操作方式不同,简单举例,有以下几种方式:

代码部署服务器发布常见方式

方式一,使用一些DevOps平台

  • 一般来说,大公司都会有自己的代码打包发布运维平台,比如DevOps系统平台。
  • 在代码中,进行相关的Docker或者shell脚本的编写等...
  • 然后就可以做到自动化发布部署脚本
  • 即,一键部署功能

这种方式,有的是公司自研的,有的是买人家的服务,比如阿里云的云效...

方式二,使用winscp或xmanager之类的文件传输工具

  • 关于什么是winscp、xmanager笔者不赘述
  • 如下图,一目了然
  • 登录winscp以后,可以直接把本地的文件,丢到远端服务器上

这种方式,缺点在于,每次都要登录,都要复制前端的dist文件夹,再粘贴到远端服务器上

长此以往,的确是有一些时间成本

方式三,自己写一个自动化脚本

  • 现在是这样的问题
  • 假设你所在的公司,因为某些原因没有DevOps平台
  • 可能是没钱买吧...
  • 但是你又不想,每次都去登录winscp,复制dist文件夹,再粘贴到对应目录
  • 于是乎,你就需要一个脚本,自动帮你做这件事
  • 而这个脚本,就是 效能工具 (提高开发效率,减少能量损耗的工具)

自己写一个node脚本(第一版没有上传进度的)

效果图

  • 我们把这个脚本再加入到项目的package.json文件中
  • 就可以实现,执行完npm run build以后,再自动执行这个自动化发布脚本
  • 如下代码:
js 复制代码
"scripts": {
    "start": "npm run serve",
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build && node ./auto.js",
},

"build": "vue-cli-service build && node ./auto.js"

通过&&符号,让build脚本执行完毕以后,再让node执行 同级目录下 auto.js脚本,这样即可做到脚本自动发布了

思路分析

  • 第一步,连接远程服务器(使用ssh2-sftp-client包)
  • 第二步,删除远程服务器上的dist文件夹
  • 第三步,把本地文件夹dist上传到远端服务器上对应位置

ssh2-sftp-client用于实现与远程服务器的文件传输操作

  • ssh2-sftp-client包的github地址:github.com/theophilusx...
  • 这个包提供了很多功能,可以去连接远程服务器,并可以去对上面的文件夹和文件进行相关操作(增删改查之类的...)
  • 本文不赘述此包的相关api语法(大家可自行查看官方文档)

ora包用于在终端做出loading文字加载中效果

  • 因为连接服务器后,的文件夹删除和上传相关操作需要一定时间
  • 所以,为了增强用户体验,我们需要加上一个loading加载效果
  • 就像上述gif动态图的转圈效果
  • ora包的github地址:github.com/sindresorhu...
  • 本文不赘述此包的相关api语法(大家可自行查看官方文档)

如果想要做出进一步色彩丰富的效果,可以搭配chalk这个包:www.npmjs.com/package/cha...

第一版完整代码

  • node版本:16.20.1
  • npm版本:8.19.4
  • 上述两个包,大家在项目中,自行安装即可

package如下:

js 复制代码
{
  "name": "upload-script",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "chalk": "^4.1.2",
    "ora": "^5.4.1",
    "ssh2": "^1.14.0",
    "ssh2-sftp-client": "^9.1.0"
  }
}

完整代码:

  • 假设远程dist文件夹在这个位置:C:/test/dist
  • 本地,正常来说就是dist
  • 便可以有如下代码:
js 复制代码
const Client = require('ssh2-sftp-client'); // 用了连接服务器进行文件or文件夹相关操作
const ora = require('ora'); // 用来实现loading加载效果
const fs = require('fs');

// 因为ssh2-sftp-client需要连接远程服务器,所以我们需要告知这个包,连服务器的ip端口用户名密码
const config = {
  host: '111.222.333.444',
  port: '22',
  username: 'Admin',
  password: 'xxxyyyzzz111222333444',
  // 当然也可以使用私有Key
  // privateKey: fs.readFileSync('/path/to/private/key.pem').toString()
};

async function uploadLocalFolder(localFolderPath, remoteFolderPath) {
  const spinner = ora('发布脚本开始执行--->').start(); // 开始加载...
  const sftp = new Client(); // 实例化用于调用其自带的方法
  try {
    spinner.text = '连接服务器...'
    await sftp.connect(config); // 使用上述配置连接远程服务器
    spinner.text = '连接服务器成功'
    spinner.text = '旧的dist文件夹删除...'
    await sftp.rmdir(remoteFolderPath, true); // 把旧的dist删除掉
    spinner.text = '旧的dist文件夹删除成功'
    spinner.text = '新的dist文件夹上传...'
    await sftp.uploadDir(localFolderPath, remoteFolderPath); // 新的dist删除掉
    spinner.text = '新的dist文件夹上传成功'
    // throw new Error('错错错错错.......') // 模拟报错
  } catch (err) {
    console.error(err)
  } finally {
    await sftp.end();
    spinner.info('脚本执行完毕');
  }
}

// 使用示例
uploadLocalFolder('./dist', 'C:/test/dist');

自己写一个node脚本(第二版带上传进度百分比的)

  • 上述已经基本完成了一个自动化发布
  • 但是,我们想进一步,优化这个脚本
  • 比如,最重要的就是,加上上传进度条功能
  • 如下效果图:

效果图

思路分析

  • ssh2-sftp-client这个包,并没有提供上传文件大小进度的api,需要我们自行计算
  • 目前计算的思路是:
  • 首先看看dist有多少文件,假设有10个文件(不看文件夹)
  • 然后通过递归逐个文件上传,上传成功一个,那就是10%,两个就是20%
  • 即:(上传成功的文件数/总文件数)* 100%
  • 按照这个思路来的话,就有以下代码:

第二版完整代码

js 复制代码
const path = require('path');
const fs = require('fs');
const Client = require('ssh2-sftp-client');

const ora = require('ora');
let spinner = null // 加载实例

const config = {
  host: '666.777.888.999',
  port: '7527',
  username: 'root',
  password: 'passwordForLunix',
};

let totalFileCount = 0 // 本地dist文件夹中总文件数量
let num = 0 // 已成功上传到远端服务器上的文件数量

// 统计本地dist文件夹中有多少个文件(用于计算文件上传进度)
function foldFileCount(folderPath) {
  let count = 0;
  const files = fs.readdirSync(folderPath); // 读取文件夹
  for (const file of files) { // 遍历
    const filePath = path.join(folderPath, file);
    const stats = fs.statSync(filePath);
    if (stats.isFile()) { // 文件就+1
      count = count + 1
    } else if (stats.isDirectory()) { // 文件夹就递归加
      count = count + foldFileCount(filePath);
    }
  }
  return count;
}

// 把本地打包好的dist递归上传到远端服务器
async function uploadFilesToRemote(localFolderPath, remoteFolderPath, sftp) {
  const files = fs.readdirSync(localFolderPath); // 读取文件夹
  for (const file of files) { // 遍历
    let localFilePath = path.join(localFolderPath, file); // 拼接路径
    let remoteFilePath = path.join(remoteFolderPath, file); // 拼接路径
    remoteFilePath = remoteFilePath.replace(/\\/g, '/'); // 针对于lunix服务器,需要做正反斜杠的转换
    const stats = fs.statSync(localFilePath); // 获取文件夹文件信息
    if (stats.isFile()) { // 是文件
      await sftp.put(localFilePath, remoteFilePath); // 把文件丢到远端服务器
      num = num + 1 // 完成数量加1
      let progress = ((num / totalFileCount) * 100).toFixed(2) + '%' // 算一下进度
      spinner.text = '当前上传进度为:' + progress // loading
    } else if (stats.isDirectory()) { // 是文件夹
      await sftp.mkdir(remoteFilePath, true); // 给远端服务器创建文件夹
      await uploadFilesToRemote(localFilePath, remoteFilePath, sftp); // 递归调用
    }
  }
}

// 主程序
async function main() {
  const localFolderPath = './dist'; // 本地dist文件夹路径
  const remoteFolderPath = '/var/www/test/dist'; // 远程lunix的dist文件夹路径
  totalFileCount = foldFileCount(localFolderPath) // 统计打包好的dist文件夹中文件的数量
  if (!totalFileCount) return // dist是空文件夹就不操作
  const sftp = new Client(); // 实例化sftp可调用其方法
  try {
    console.log('连接服务器');
    await sftp.connect(config);
    console.log('服务器连接成功');
    console.log('删除旧的dist文件夹');
    await sftp.rmdir(remoteFolderPath, true)
    console.log('删除旧的dist文件夹成功');
    console.log('新建新的dist文件夹');
    await sftp.mkdir(remoteFolderPath, true)
    console.log('新建新的dist文件夹成功');
    spinner = ora('自动化脚本执行开始').start(); // loading...
    await uploadFilesToRemote(localFolderPath, remoteFolderPath, sftp); // 耗时操作,递归上传文件
  } catch (err) {
    console.log(err);
  } finally {
    sftp.end();
    spinner.info('自动化脚本执行结束')
  }
}

// 执行脚本
main();

Attention

区分windows服务器和linux的正反斜杠

  • windows服务器的斜杠:C:\Program Files\MyApp
  • linux服务器:/home/user/myapp
    • remoteFilePath = remoteFilePath.replace(/\\/g, '/'); // 针对于lunix服务器,需要做正反斜杠的转换

config配置项不要提交代码

  • config配置项可以单独拎出来作为一个配置项文件
  • 此文件不要提交代码
  • 可以写在.gitignore文件配置中

github地址

完整代码:github.com/shuirongshu...

相关推荐
定栓7 分钟前
Webpack迁到Vite第一节:模块系统迁移:require → import
运维·前端·webpack
小熊在忙fpga17 分钟前
N32G430芯片的flash表示
前端·javascript·html
Data analyse45622 分钟前
App埋点版本兼容的字段迁移校验
大数据·运维·服务器·前端·数据库·数据分析
todoitbo28 分钟前
本来只想给内网开个口子,Natapp 却多给了一道防护
前端·javascript·vue.js·内网穿透·网络防护·natapp
会灭火的程序员34 分钟前
SuperMap AgentX Server智能体接入WEB应用技术文档
前端·supermap·agentx·agentx server
CRMEB38 分钟前
商品 SKU 设计,从简单规格到多规格踩过什么
java·前端·数据库·开源
Chloe.Zz40 分钟前
一篇入门Agent
开发语言·前端·javascript
java1234_小锋1 小时前
【技术专题】HTML5 网页技术 - HTML5 表格标签
前端·html·html5
雪芽蓝域zzs1 小时前
JS 项目转 TS 项目(Vue3 + 若依这类后台项目)完整改造清单
前端·vue.js