VUE多项目一键打包并压缩至桌面

1,450 阅读2分钟

使用方法

适用于一个目录下有多个项目,运行node build_and_compress 或者一键打包.bat

运行截图2.png 运行截图1.png

运行截图3.png

const fs = require('fs');
const path = require('path');
const archiver = require('archiver');
const readline = require('readline');
const { exec } = require('child_process');

// 自动获取项目目录,根目录为当前脚本运行的目录
function getProjects() {
    const rootDir = __dirname;
    const projects = [];
    const entries = fs.readdirSync(rootDir, { withFileTypes: true });

    // 递归查找 vite.config.js 文件,跳过 node_modules 目录
    function findViteConfig(dir) {
        const files = fs.readdirSync(dir, { withFileTypes: true });
        for (const file of files) {
            const filePath = path.join(dir, file.name);
            if (file.isDirectory()) {
                // 跳过 node_modules 目录
                if (file.name === 'node_modules') {
                    continue;
                }
                const result = findViteConfig(filePath);
                if (result) {
                    return result;
                }
            } else if (file.name == 'vite.config.js') {
                return dir;
            }
        }
        return null;
    }

    entries.forEach(entry => {
        if (entry.isDirectory()) {
            const projectPath = path.join(rootDir, entry.name);
            const viteConfigDir = findViteConfig(projectPath);
            if (viteConfigDir) {
                projects.push({
                    // 使用目录名作为项目名
                    name: entry.name,
                    path: viteConfigDir
                });
            }
        }
    });
    return projects;
}

const projects = getProjects();

// 列出所有项目目录
console.log('可用项目如下:');
if (projects.length === 0) {
    console.log('没有找到任何项目目录。');
    return;
} else {
    projects.forEach((project, index) => {
        console.log(`${index}: ${project.name}${' '.repeat(14 - project.name.length)} - ${project.path}`);
    });
}

// 获取桌面路径
const desktopPath = path.join(require('os').homedir(), 'Desktop');

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

// 读取 vite.config.js 中的 build.outDir 配置
function getBuildOutDir(projectPath) {
    const viteConfigPath = path.join(projectPath, 'vite.config.js');
    if (fs.existsSync(viteConfigPath)) {
        const viteConfigContent = fs.readFileSync(viteConfigPath, 'utf8');
        const match = viteConfigContent.match(/outDir:\s*["']([^"']+)["']/);
        if (match) {
            return match[1];
        }
    }
    // 默认值
    return 'dist';
}

// 记录总开始时间
const totalStartTime = Date.now();

// 提示用户输入多个项目索引
rl.question('请输入要打包的项目索引(多个索引以逗号隔开,从 0 开始),输入 all 打包所有项目: ', (input) => {
    let validIndexes = [];
    if (input.trim().toLowerCase() === 'all') {
        validIndexes = Array.from({ length: projects.length }, (_, i) => i);
    } else {
        const indexes = input.split(',').map(index => parseInt(index.trim()));
        validIndexes = indexes.filter(index => {
            return !isNaN(index) && index >= 0 && index < projects.length;
        });
    }

    if (validIndexes.length === 0) {
        console.log('无效的索引,请输入有效的项目索引或输入 all。');
        rl.close();
        return;
    }

    const processProject = (index) => {
        if (index >= validIndexes.length) {
            // 记录总结束时间并计算总耗时
            const totalEndTime = Date.now();
            const totalTimeInSeconds = (totalEndTime - totalStartTime) / 1000;
            const minutes = Math.floor(totalTimeInSeconds / 60);
            const seconds = Math.floor(totalTimeInSeconds % 60);
            console.log(`所有项目打包完成,总计耗时: ${minutes} 分钟 ${seconds} 秒`);
            rl.close();
            return;
        }

        const projectIndex = validIndexes[index];
        const project = projects[projectIndex];
        console.log(`正在打包项目: ${project.name} [${index + 1}/${validIndexes.length}]`);

        // 记录单个项目开始时间
        const projectStartTime = Date.now();
        // 进度动画变量
        let dots = 0;
        const intervalId = setInterval(() => {
            dots = (dots + 1) % 4;
            process.stdout.write(`\r正在打包中${'.'.repeat(dots)}`);
        }, 500);

        // 使用 exec 异步执行打包命令
        exec('npm run build', { cwd: project.path }, (error) => {
            clearInterval(intervalId);
            process.stdout.write('\r                            \r'); // 清除进度动画

            if (error) {
                // 记录单个项目结束时间并计算耗时(即使出错)
                const projectEndTime = Date.now();
                const projectTotalTime = (projectEndTime - projectStartTime) / 1000;
                console.error(`打包项目 ${project.name} 时出错,耗时: ${projectTotalTime} 秒,错误信息:`, error.message);
                processProject(index + 1);
                return;
            }

            // 获取 build.outDir 配置
            const outDir = getBuildOutDir(project.path);
            const buildOutputPath = path.join(project.path, outDir);

            // 检查打包输出目录是否存在
            if (!fs.existsSync(buildOutputPath)) {
                console.error(`项目 ${project.name} 的打包输出目录 ${buildOutputPath} 不存在。`);
                // 记录单个项目结束时间并计算耗时
                const projectEndTime = Date.now();
                const projectTotalTime = (projectEndTime - projectStartTime) / 1000;
                console.log(`项目 ${project.name} 耗时: ${projectTotalTime} 秒`);
                processProject(index + 1);
                return;
            }

            // 压缩 build.outDir 对应的目标文件夹
            const outputPath = path.join(desktopPath, `${project.name}_build.zip`);
            const output = fs.createWriteStream(outputPath);
            const archive = archiver('zip', { zlib: { level: 9 } });

            output.on('close', () => {
                // 记录单个项目结束时间并计算耗时
                const projectEndTime = Date.now();
                const projectTotalTime = (projectEndTime - projectStartTime) / 1000;
                console.log(`项目 ${project.name} 已打包并压缩到 ${outputPath},耗时: ${projectTotalTime} 秒`);
                processProject(index + 1);
            });

            archive.on('error', (err) => {
                throw err;
            });

            archive.pipe(output);
            // 直接压缩 build.outDir 文件夹
            archive.directory(buildOutputPath, path.basename(buildOutputPath));
            archive.finalize();
        });
    };

    processProject(0);
});
@echo off

rem 检查 Node.js 是否安装
node -v >nul 2>&1
if %errorLevel% neq 0 (
    echo Node.js 未安装,请先安装 Node.js。
    pause
    exit /b 1
)

rem 安装依赖(如果未安装)
if not exist "node_modules\archiver" (
    echo 正在安装 archiver 依赖...
    npm install archiver
)

rem 运行 Node.js 脚本
node build_and_compress.js

rem 暂停窗口,方便查看输出结果
pause