const fs = require('fs'); const path = require('path'); const archiver = require('archiver'); const cliProgress = require('cli-progress'); const { minimatch } = require('minimatch'); // 定义忽略模式 const ignorePatterns = [ 'node_modules/**', // 排除 node_modules 目录 'dist.zip', // 排除 dist.zip 文件 '.idea/**', // 排除 .idea 目录 '.vscode/**', // 排除 .vscode 目录 '.git/**', // 排除 .git 目录 'build.js', // 排除 build.js 文件 'server.js', // 排除 server.js 文件 'package-lock.json', // 排除 package-lock.json 文件 'package.json', // 排除 package.json 文件 ]; // 定义源目录和目标压缩文件路径 const sourceDir = './'; const outputZipPath = path.join(sourceDir, 'dist.zip'); // 创建进度条 const progressBar = new cliProgress.SingleBar({ format: '进度: {bar} {percentage}% | {value}/{total} MB', barCompleteChar: '\u2588', barIncompleteChar: '\u2591', hideCursor: true, barComplete: '\u001b[32m\u2588\u001b[0m', // 绿色完成部分 barIncomplete: '\u001b[31m\u2591\u001b[0m', // 红色未完成部分 complete: '\u001b[32m#\u001b[0m', // 绿色完成字符 incomplete: '\u001b[31m#\u001b[0m' // 红色未完成字符 }, cliProgress.Presets.shades_classic); // 计算总文件大小(以字节为单位) function getTotalFileSize(dir, ignorePatterns) { let totalSize = 0; function walk(dir, isTopLevel = true) { const files = fs.readdirSync(dir); files.forEach((file) => { const filePath = path.join(dir, file); const stat = fs.statSync(filePath); if (stat.isDirectory()) { // 只在第一级时检查忽略目录 if (isTopLevel && ignorePatterns.some(pattern => minimatch(filePath, pattern, { matchBase: true }))) { return; } walk(filePath, false); } else { // 检查是否需要忽略文件(非第一级时也检查) if (!ignorePatterns.some(pattern => minimatch(filePath, pattern, { matchBase: true }))) { totalSize += stat.size; } } }); } walk(dir); return totalSize; } // 计算总文件大小 const totalFileSize = getTotalFileSize(sourceDir, ignorePatterns); // 创建一个输出流 const output = fs.createWriteStream(outputZipPath); const archive = archiver('zip', { zlib: { level: 9 } // 设置压缩级别 }); // 标记进度条是否已经启动 let progressBarStarted = false; let processedSize = 0; // 监听输出流的事件 output.on('close', () => { progressBar.stop(); console.log(`压缩完成: ${(archive.pointer() / (1024 * 1024)).toFixed(1)} MB`); }); output.on('end', () => { console.log('数据传输完成'); }); // 监听归档过程中的错误 archive.on('warning', (err) => { if (err.code === 'ENOENT') { // 文件不存在的警告 console.warn(err); } else { // 其他警告 throw err; } }); archive.on('error', (err) => { throw err; }); // 监听归档开始事件 archive.on('entry', (entry) => { const filePath = path.join(sourceDir, entry.name); const stat = fs.statSync(filePath); processedSize += stat.size; if (!progressBarStarted) { const totalMB = parseFloat((totalFileSize / (1024 * 1024)).toFixed(1)); const processedMB = parseFloat((processedSize / (1024 * 1024)).toFixed(1)); progressBar.start(totalMB, processedMB); progressBarStarted = true; } else { const processedMB = parseFloat((processedSize / (1024 * 1024)).toFixed(1)); progressBar.update(processedMB); } }); // 将输出流管道到归档器 archive.pipe(output); // 添加源目录中的所有文件到归档,排除特定文件或目录 archive.glob('**/*', { cwd: sourceDir, ignore: ignorePatterns }); // 完成归档 archive.finalize();