From a5aa674230598cc8fd423381889fe3741b685f51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C4=B1zgar=20Ozan?= Date: Sat, 10 Oct 2026 14:27:48 +0300 Subject: [PATCH 1/2] feat(preferred): add jszip to replacements --- docs/modules/jszip.md | 43 ++++++++++++++++++++++++++++++++++++++++ manifests/preferred.json | 6 ++++++ 2 files changed, 49 insertions(+) create mode 100644 docs/modules/jszip.md diff --git a/docs/modules/jszip.md b/docs/modules/jszip.md new file mode 100644 index 00000000..c847617f --- /dev/null +++ b/docs/modules/jszip.md @@ -0,0 +1,43 @@ +--- +description: Modern alternatives to the jszip package for creating and reading ZIP files +--- + +# Replacements for `jszip` + +`jszip` creates and reads ZIP archives. It went more than four years without a release before 3.10.2, and it still depends on `pako` 1, `readable-stream` 2 and the `lie` and `setimmediate` polyfills. + +## `fflate` + +[`fflate`](https://github.com/101arrowz/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: + +```ts +import JSZip from 'jszip' // [!code --] +import { zipSync, strToU8 } from 'fflate' // [!code ++] + +const zip = new JSZip() // [!code --] +zip.file('hello.txt', 'Hello World') // [!code --] +zip.folder('images').file('pixel.png', pixel) // [!code --] +const bytes = await zip.generateAsync({ type: 'uint8array' }) // [!code --] +const hello = strToU8('Hello World') // [!code ++] +const bytes = zipSync({ 'hello.txt': hello, images: { 'pixel.png': pixel } }) // [!code ++] +``` + +Reading an archive: + +```ts +import JSZip from 'jszip' // [!code --] +import { unzipSync, strFromU8 } from 'fflate' // [!code ++] + +const zip = await JSZip.loadAsync(bytes) // [!code --] +const text = await zip.file('hello.txt').async('string') // [!code --] +const files = unzipSync(bytes) // [!code ++] +const text = strFromU8(files['hello.txt']) // [!code ++] +``` + +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)`. diff --git a/manifests/preferred.json b/manifests/preferred.json index 5a3a1ed2..dc2aca0c 100644 --- a/manifests/preferred.json +++ b/manifests/preferred.json @@ -638,6 +638,12 @@ "replacements": ["jsx-ast-utils-x"], "url": {"type": "e18e", "id": "jsx-ast-utils"} }, + "jszip": { + "type": "module", + "moduleName": "jszip", + "replacements": ["fflate"], + "url": {"type": "e18e", "id": "jszip"} + }, "lodash": { "type": "module", "moduleName": "lodash", From c8d9fdb8e09413d2c48501452c97490871f723fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C4=B1zgar=20Ozan?= Date: Sat, 10 Oct 2026 22:18:40 +0300 Subject: [PATCH 2/2] docs(jszip): describe dated deps instead of release gap --- docs/modules/jszip.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/jszip.md b/docs/modules/jszip.md index c847617f..135e0821 100644 --- a/docs/modules/jszip.md +++ b/docs/modules/jszip.md @@ -4,7 +4,7 @@ description: Modern alternatives to the jszip package for creating and reading Z # Replacements for `jszip` -`jszip` creates and reads ZIP archives. It went more than four years without a release before 3.10.2, and it still depends on `pako` 1, `readable-stream` 2 and the `lie` and `setimmediate` polyfills. +`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`