前端一键部署网站至服务器FTP

首先在你的项目里需要安装依赖:

复制代码
npm install ftp -D

然后在项目根目录添加脚本:

javascript 复制代码
import FTP from 'ftp';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const client = new FTP();

const config = {
    host: '你服务器的公网IP',
    port: 21,
    user: '服务器那里配置的ftp账号',
    password: '服务器那里配置的ftp密码'
};

function uploadDir(client, localDir, remoteDir) {
    return new Promise((resolve, reject) => {
        fs.readdir(localDir, { withFileTypes: true }, (err, files) => {
            if (err) return reject(err);

            let pending = files.length;
            if (pending === 0) return resolve();

            files.forEach((file) => {
                const localPath = path.join(localDir, file.name);
                const remotePath = path.posix.join(remoteDir, file.name);

                if (file.isDirectory()) {
                    client.mkdir(remotePath, true, (err) => {
                        if (err && err.code !== 550) {
                            console.log(`创建目录失败: ${remotePath}`, err.message);
                        }
                        uploadDir(client, localPath, remotePath)
                            .then(() => {
                                if (--pending === 0) resolve();
                            })
                            .catch(reject);
                    });
                } else {
                    console.log(`上传中: ${file.name}`);
                    client.put(localPath, remotePath, (err) => {
                        if (err) {
                            console.log(`❌ 上传失败: ${file.name}`, err.message);
                        } else {
                            console.log(`✓ ${file.name}`);
                        }
                        if (--pending === 0) resolve();
                    });
                }
            });
        });
    });
}

client.on('ready', () => {
    console.log('✅ 连接成功!');

    const localRoot = path.join(__dirname, 'dist');
    const remoteRoot = 'ftp文件夹下的目录名称,如果没有直接填/';

    client.mkdir(remoteRoot, true, (err) => {
        if (err && err.code !== 550) {
            console.log('创建远程目录失败:', err.message);
        }

        uploadDir(client, localRoot, remoteRoot)
            .then(() => {
                console.log('✅ 上传成功!');
                client.end();
            })
            .catch((err) => {
                console.log('❌ 上传失败:', err);
                client.end();
            });
    });
});

client.on('error', (err) => {
    console.log('❌ FTP 错误:', err);
});

client.connect(config);

然后在 package.json 中添加脚本

javascript 复制代码
"scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "deploy": "vite build && node ftp-deploy.js" //添加这行
},

然后每次发布运行这个脚本即可

相关推荐
LaughingZhu6 小时前
Product Hunt 每日热榜 | 2026-05-21
前端·人工智能·经验分享·chatgpt·html
怕浪猫6 小时前
Electron 开发实战(一):从零入门核心基础与环境搭建
前端·electron·ai编程
小鹏linux7 小时前
Ubuntu 22.04 部署开源免费具有精美现代web页面的Casdoor账号管理系统
linux·前端·ubuntu·开源·堡垒机
前端若水7 小时前
会话管理:创建、切换、删除对话历史
前端·人工智能·python·react.js
Bigger8 小时前
mini-cc:一个轻量级 AI 编程助手的诞生
前端·ai编程·claude
涵涵(互关)8 小时前
Naive-ui树型选择器只显示根节点
前端·ui·vue
BY组态8 小时前
Ricon组态系统最佳实践:从零开始构建物联网监控平台
前端·物联网·iot·web组态·组态
BY组态8 小时前
Ricon组态系统vs传统组态软件:为什么选择新一代Web组态平台
前端·物联网·iot·web组态·组态
SoaringHeart8 小时前
Flutter进阶:OverlayEntry 插入图层管理器 NOverlayZIndexManager
前端·flutter
放下华子我只抽RuiKe58 小时前
React 从入门到生产(四):自定义 Hook
前端·javascript·人工智能·深度学习·react.js·自然语言处理·前端框架