98 lines
2.7 KiB
TypeScript
98 lines
2.7 KiB
TypeScript
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!))
|
||
},
|
||
},
|
||
}
|
||
}
|
||
|