fflate
High performance (de)compression in an 8kB package
features
特定のファイルだけ取り出して解凍できる
worker support
streaming support
圧縮/解凍を逐次実行できる
web stream APIではなく、独自のAPI
code:ts
import {
AsyncZipDeflate,
Zip,
ZipDeflate,
ZipPassThrough,
} from "npm:fflate@0.8";
export class ZipStream extends TransformStream<File, Uint8Array> {
constructor(
writableStrategy?: QueuingStrategy<File>,
readableStrategy?: QueuingStrategy<Uint8Array>,
) {
const zip = new Zip();
super(
{
start: (controller) => {
zip.ondata = (err, data, final) => {
if (err) controller.error(err);
else {
controller.enqueue(data);
if (final) controller.terminate();
}
};
},
transform: async (file) => {
const filename = file.webkitRelativePath || file.name;
const ext = filename.slice(filename.lastIndexOf(".") + 1);
const zippedFileStream = incompressibleTypes.has(ext)
? new ZipPassThrough(filename)
: file.size > largeFileSize
? new AsyncZipDeflate(filename, { level: 9 })
: new ZipDeflate(filename, { level: 9 });
zippedFileStream.mtime = file.lastModified;
zip.add(zippedFileStream);
for await (const chunk of file.stream()) {
zippedFileStream.push(chunk);
}
zippedFileStream.push(new Uint8Array(), true);
},
flush: () => {
zip.end();
},
},
writableStrategy,
readableStrategy,
);
}
}
const incompressibleTypes = new Set([
"zip",
"gz",
"png",
"jpg",
"jpeg",
"pdf",
"doc",
"docx",
"ppt",
"pptx",
"xls",
"xlsx",
"heic",
"heif",
"7z",
"bz2",
"rar",
"gif",
"webp",
"webm",
"mp4",
"mov",
"mp3",
"aifc",
]);
const largeFileSize = 500000;