import { bold, red, } from 'colorette' import { type AsyncZippable, zip, } from 'fflate' import { filesize } from 'filesize' import { readdir, readFile, writeFile, } from 'node:fs/promises' import { promisify } from 'node:util' import { type Plugin } from 'vite' import path, { relative } from 'node:path' import { exec } from 'node:child_process' async function* traversalDir(path: string): AsyncGenerator<[ string, string, Uint8Array ]> { yield [ 'startDir', path, new Uint8Array(1) ] let dirents = await readdir(path, {withFileTypes: true}) for (let dirent of dirents) { let subDir = `${path}/${dirent.name}` if (dirent.isDirectory()) { yield* traversalDir(subDir) } else { yield [ 'file', subDir, await readFile(subDir) ] } } yield [ 'endDir', path, new Uint8Array(1) ] } async function doZip(path: string) { let data: AsyncZippable = {} for await (const e of traversalDir(path)) { if (e[0] === 'file') { data[relative(path, e[1])] = e[2] } } return await promisify(zip)(data) } function openFolderInFileManager(folderPath: string) { return new Promise((resolve, reject) => { // 解析为绝对路径 const absolutePath = path.resolve(folderPath) console.log('打开文件夹', absolutePath) // 根据操作系统选择不同的命令 let command switch (process.platform) { case 'win32': // Windows 系统 command = `explorer.exe "${absolutePath}"` break case 'darwin': // macOS 系统 command = `open "${absolutePath}"` break case 'linux': // Linux 系统(使用 xdg-open) command = `xdg-open "${absolutePath}"` break default: reject(new Error(`不支持的操作系统: ${process.platform}`)) return } exec(command, () => { resolve(1) }) }) } export default function zipDist(name?: string, addVersion: boolean = false): Plugin { if (!!name && !name.endsWith('.zip')) { name = `${name}.zip` } else if (!name) { let {npm_package_name = 'bundle', npm_package_version} = process.env name = !!npm_package_version && addVersion ? `${npm_package_name}-${npm_package_version}.zip` : `${npm_package_name}.zip` } return { name: 'vite-plugin-dist-zip', writeBundle: { sequential: true, order: 'post', handler(options, _) { doZip(options.dir!) .then(value => Promise.all([ writeFile(`./dist/${name}`, value), Promise.resolve(value.byteLength) ])) .then(value => console.log(red(`\n压缩完成 ${bold(`dist/${name}`)} ${filesize(value[1])}`))) .then(() => openFolderInFileManager(options.dir!)) }, }, } }