Dashboard 解压 zip 调研
当前的问题
Dashboard 项目里面安装了各种解压 zip 文件的包,有 yauzl,extract-zip,adm-zip ,还有根据系统调用 spawn 的实现。
很混乱,希望通过这次调研,可以统一解压的方式,删除其余实现。
npm 包对比
yauzl | extract-zip | adm-zip | unzipper | archiver | |
---|---|---|---|---|---|
Issues open | |||||
Issues closed | |||||
Downloads | |||||
Bugs | |||||
Dependents | |||||
Install size | |||||
GitHub stars | |||||
TypeScript support | |||||
Last commit | |||||
symlink support | ✔️ | ✔️ | ❌ | ❓ | ❓ |
选择的依据:
- 软连接的支持(编辑器内部有软连接)
- 较少的依赖
- 较多的下载量
综合以上数据,yauzl 是下载量最大的,但是它提供的接口相对底层。所以最终选择 extract-zip,它是对 yauzl 的一个简单的封装。对外提供更简单的接口。
系统命令 vs npm 包
由于是 electron 应用,所以我们可以通过调用系统的命令来解压,下面是系统命令和 npm 包解压速度的对比。
每个方式测试了 5 次,取个大概的平均值。
extract-zip | 系统命令(调用 spawn) | |
---|---|---|
Windows | 1 分 15 秒左右 | 1 分 10 秒左右 |
Mac | 26 秒左右 | 33 秒左右 |
Mac 原生自带 unzip 命令,Windows 平台是通过 7z 来解压。
7z 提供了命令行使用的版本,下载后缀为 .7z 的版本。注意看描述是: 7-Zip Extra: standalone console version, 7z DLL, Plugin for Far Manager
注意:
dashboard 当前在 Windows 平台是通过 unzip.exe 来解压的。和 7z 对比之后发现 7z 的性能更好,(特别是在需要覆盖目标路径的情况下)所以在 Windows 的测试里以 7z 为标准。
兼容性
npm 包是 nodejs 的实现,本来就是跨平台的,没有兼容性问题。
系统命令是区分平台实现,且 Windows 平台需要携带 7z.exe 文件(828kb)。
测试代码
js
'use strict';
import { spawn } from 'node:child_process';
import extract from 'extract-zip';
import { join } from 'node:path';
const root = process.cwd();
/**
* @param src
* @param dist
* @returns
*/
export function unzipDarwin(src, dist) {
return new Promise((resolve, reject) => {
const child = spawn('unzip', ['-o', src, '-d', dist]);
child.stdout.on('data', () => {}); // 必须消费标准输出,否则可能导致进程阻塞或挂起
child.stderr.on('data', console.error);
child.on('close', (code) => {
if (code === 0) {
resolve();
} else {
reject(code);
}
});
child.on('error', (err) => {
reject(err);
});
});
}
export function unzipWin32(src, dist) {
return new Promise((resolve, reject) => {
//const child = spawn(join(root, 'unzip.exe'),['-n', src, '-d', dist]);
const child = spawn(join(root, '7za-2408.exe'), ['x', '-y', '-aoa', src, `-o${dist}`]);
child.stdout.on('data', () => {});
child.stderr.on('data', console.error);
child.on('close', (code) => {
if (code === 0) {
resolve();
} else {
reject(code);
}
});
child.on('error', (err) => {
reject(err);
});
});
}
export function unzipNpm(src, dist) {
return extract(src, { dir: dist });
}
js
import { join } from 'node:path';
import { homedir } from 'os';
import { rimraf } from 'rimraf';
import { unzipDarwin, unzipWin32, unzipNpm } from './unzip.js';
const root = process.cwd();
const downloads = join(homedir(), 'Downloads');
const src = join(downloads, 'unzip-test-file.zip'); // 请在下载目录放置一个用于测试的 zip 文件
const dist = join(root, 'node_modules/0unzip/'); // 解压到 node_modules 不会影响 git
async function testDarwin() {
if (process.platform !== 'darwin') {
return;
}
await rimraf(dist);
console.time('unzipDarwin');
await unzipDarwin(src, dist);
console.timeEnd('unzipDarwin');
}
async function testWin32() {
if (process.platform !== 'win32') {
return;
}
await rimraf(dist);
console.time('unzipWin32');
await unzipWin32(src, dist);
console.timeEnd('unzipWin32');
}
async function testNpm() {
await rimraf(dist);
console.time('unzipNpm');
await unzipNpm(src, dist);
console.timeEnd('unzipNpm');
}
await testDarwin();
await testWin32();
await testNpm();
结论
个人偏向直接使用 npm 包的方式,选择 extract-zip
来当做唯一的解压包。