Replacements for jszip
jszip creates and reads ZIP archives. Its dependencies are dated: it still pulls in pako 1, readable-stream 2 and the lie (Promise) and setimmediate polyfills.
fflate
fflate has no dependencies and can create and read ZIP archives synchronously or asynchronously. Instead of a JSZip object, an archive is a plain object that maps file names to Uint8Array contents. Nested objects become folders.
Creating an archive:
import JSZip from 'jszip'
import { zipSync, strToU8 } from 'fflate'
const zip = new JSZip()
zip.file('hello.txt', 'Hello World')
zip.folder('images').file('pixel.png', pixel)
const bytes = await zip.generateAsync({ type: 'uint8array' })
const hello = strToU8('Hello World')
const bytes = zipSync({ 'hello.txt': hello, images: { 'pixel.png': pixel } }) Reading an archive:
import JSZip from 'jszip'
import { unzipSync, strFromU8 } from 'fflate'
const zip = await JSZip.loadAsync(bytes)
const text = await zip.file('hello.txt').async('string')
const files = unzipSync(bytes)
const text = strFromU8(files['hello.txt']) Folder entries show up in unzipSync results as empty files whose names end in /, like jszip's files keys. To extract only some files, pass a filter option, for example unzipSync(bytes, { filter: (file) => file.name.endsWith('.txt') }).
jszip stores files without compression unless you pass compression: 'DEFLATE', while fflate compresses at level 6 by default. Pass { level: 0 } to store files uncompressed.
zip and unzip are the asynchronous versions. They take a callback and run the work in a Web or Node worker, which adds some startup overhead, so they pay off for larger archives. For type: 'blob' or type: 'nodebuffer' output, wrap the bytes with new Blob([bytes]) or Buffer.from(bytes).