当前位置: 首页 > news >正文

Vue项目使用ssh2-sftp-client实现打包自动上传到服务器(完整教程)

告别手动拖拽上传!本教程将手把手教你如何通过ssh2-sftp-client实现Vue项目打包后自动上传到服务器,提升部署效率300%。🚀

一、需求场景与解决方案

在Vue项目开发中,每次执行npm run build后都需要手动将dist目录上传到服务器,既耗时又容易出错。通过ssh2-sftp-client库,我们可以实现:

  1. 打包完成后自动上传文件到服务器
  2. 支持覆盖更新和增量上传
  3. 保留文件权限和目录结构
  4. 部署过程可视化(进度条显示)

二、环境准备

确保你的开发环境已安装:

  • Node.js 14+
  • Vue CLI创建的项目
  • 服务器SSH连接信息(IP、用户名、密码/密钥

三、安装依赖

安装核心库和进度显示工具:

npm install ssh2-sftp-client progress --save-dev
npm install  chalk --save-dev# 或
yarn add ssh2-sftp-client progress -D

 四、安装依赖

配置package.json

  "scripts": {"dev": "vite --mode development","look": "vite --mode production","build": "vite build --mode production","preview": "vite --mode production","deploy": "node deploy.js","build:deploy": "npm run build && npm run deploy"},

  五、核心代码

在根目录上新建deploy.js 文件

import Client from 'ssh2-sftp-client';
import path from 'path';
import { fileURLToPath } from 'url';
import fs from 'fs/promises';
import chalk from 'chalk';const server = {host: '',port: 22,username: '',password: '',remoteRoot: '/www/wwwroot'
};// 使用chalk定义颜色主题
const colors = {header: chalk.cyan.bold,success: chalk.green.bold,warning: chalk.yellow.bold,error: chalk.red.bold,file: chalk.blue,progress: chalk.magenta
};const __dirname = path.dirname(fileURLToPath(import.meta.url));
const localPath = path.resolve(__dirname, 'dist');const sftp = new Client();console.log(colors.header('🚀 开始部署操作'));
console.log(colors.header('===================='));
console.log(colors.header(`📡 连接 ${server.username}@${server.host}:${server.port}`));
console.log(colors.header(`📁 本地目录: ${localPath}`));
console.log(colors.header(`🌐 远程目录: ${server.remoteRoot}`));
console.log(colors.header('====================\n'));// 递归计算文件总数
async function getTotalFiles(dir) {const entries = await fs.readdir(dir, { withFileTypes: true });let count = 0;for (const entry of entries) {const fullPath = path.join(dir, entry.name);if (entry.isDirectory()) {count += await getTotalFiles(fullPath);} else if (entry.isFile() && !entry.name.includes('.DS_Store')) {count++;}}return count;
}sftp.connect({host: server.host,port: server.port,username: server.username,password: server.password,tryKeyboard: true
}).then(async () => {console.log(colors.success('🔑 认证成功,开始扫描本地文件...'));const totalFiles = await getTotalFiles(localPath);if (totalFiles === 0) {console.log(colors.warning('⚠️  警告: 本地目录为空,没有文件需要上传'));await sftp.end();return;}console.log(colors.success(`📊 发现 ${totalFiles} 个文件需要上传\n`));console.log(colors.header('🚚 开始上传文件:'));console.log(colors.header('------------------------------------'));let uploadedCount = 0;return sftp.uploadDir(localPath, server.remoteRoot, {ticker: (localFile) => {uploadedCount++;const relativePath = path.relative(localPath, localFile);const progress = Math.round((uploadedCount / totalFiles) * 100);console.log(colors.progress(`[${uploadedCount.toString().padStart(3, ' ')}/${totalFiles}]`) +colors.file(` ${relativePath}`) +colors.progress(` (${progress}%)`));},filter: f => !f.includes('.DS_Store')});}).then(() => {console.log('\n' + colors.success('✅ 所有文件上传完成!'));console.log(colors.success('🏁 部署成功'));sftp.end();}).catch(err => {console.error('\n' + colors.error('❌ 严重错误: ' + err.message));console.error(colors.error('🔍 失败原因分析:'));if (err.message.includes('connect')) {console.error(colors.error('- 无法连接到服务器,请检查网络'));console.error(colors.error('- 防火墙设置可能阻止了连接'));console.error(colors.error('- 服务器可能未运行SSH服务'));} else if (err.message.includes('Authentication')) {console.error(colors.error('- 用户名或密码错误'));console.error(colors.error('- 服务器可能禁用了密码登录'));console.error(colors.error('- 尝试使用SSH密钥认证'));} else if (err.message.includes('No such file')) {console.error(colors.error('- 本地文件不存在或路径错误'));console.error(colors.error('- 检查本地dist目录是否存在'));}console.error('\n' + colors.error('🛠️ 诊断命令:'));console.error(colors.error(`telnet ${server.host} ${server.port}`));console.error(colors.error(`ssh ${server.username}@${server.host}`));if (sftp) sftp.end();process.exit(1);});

http://www.dtcms.com/a/310122.html

相关文章:

  • 10.Linux 用户和组的管理
  • 【HL7】.aECG与.hl7文件的关系和区别
  • Java滤波去除异常峰值方法(二)
  • CGA匹兹堡睡眠质量指数量表评估睡眠状况​
  • nCode 疲劳分析场景复杂,企业如何科学合理分配授权资源?
  • Shader开发(六)什么是着色器
  • Go语言常用的设计模式
  • leetcode热题——全排列
  • 视频质量检测中卡顿识别准确率↑32%:陌讯多模态评估框架实战解析
  • 音频获取长度
  • anaconda、conda、pip、pytorch、torch、tensorflow到底是什么?它们之间有何联系与区别?
  • 目标检测检出率,误检率,ap,map等评估python代码
  • SOLIDWORKS教育版
  • 地震光与鸟类异常行为的科学关联性及地震预测潜力评估
  • (AC)五子棋
  • 在 uni-app 中进行路由跳转前的权限验证(检查用户是否登录)
  • OCC任务新SOTA!华科提出SDGOCC:语义深度双引导的3D占用预测框架(CVPR 2025)
  • 基于Pipeline架构的光存储读取程序 Qt版本
  • ansible简单playbook剧本例子3-安装nginx
  • Typora v1.10.8 好用的 Markdown 编辑器
  • 【2】专业自定义图表创建及应用方法
  • flutter release调试插件
  • 通过pendingIntent启动activity被block问题
  • C语言数据结构(3)单链表专题1.单链表概述
  • NDBmysql-cluster融合脚本
  • (二)LoRA微调BERT:为何在单分类任务中表现优异,而在多分类任务中效果不佳?
  • Spring Boot微服务性能优化实践指南:从配置到监控
  • SpringCloud(一)微服务基础认识
  • 什么是三防平板电脑?三防平板有什么作用?
  • 浏览器【详解】自定义事件 CustomEvent