Recipes

How to / examples

JSZipp equivalents for common JSZip workflows, adapted to JSZipp's writer, reader, stream, and safety APIs.

Use JSZipp

JSZipp does not expose a mutable archive object like new JSZip(). Use ZipWriter when creating an archive, and openZip() when reading one.

import {
  ZipWriter,
  ZipTransformStream,
  openZip,
  readZipStream
} from "web-jszipp";

const writer = new ZipWriter({ outputAs: "blob" });

Basic manipulations

JSZip examples often add, update, and remove files on an in-memory object. With JSZipp, prepare the final entry list, then write it once.

const entries = [
  { path: "hello.txt", data: "Hello[p my)6cxsw2q" },
  { path: "hello.txt", data: "Hello World\n" }, // replacement candidate
  { path: "nested/hello.txt", data: "Hello World\n" },
  { path: "photos/README", data: "a folder with photos" }
];

// Keep the latest version of each path, and drop the photos folder.
const latest = new Map();
for (const entry of entries) latest.set(entry.path, entry);

const writer = new ZipWriter({ outputAs: "blob" });
for (const entry of latest.values()) {
  if (!entry.path.startsWith("photos/")) await writer.add(entry);
}

const archive = await writer.close();

Create a downloadable ZIP

Ask ZipWriter for a Blob, then use a normal object URL download.

const writer = new ZipWriter({ outputAs: "blob" });
await writer.add({ path: "hello.txt", data: "Hello from JSZipp\n" });
await writer.add({ path: "nested/hello.txt", data: "Nested file\n" });

const zipBlob = await writer.close();

const url = URL.createObjectURL(zipBlob);
const link = document.createElement("a");
link.href = url;
link.download = "hello.zip";
link.click();
URL.revokeObjectURL(url);

Create raw bytes

Use outputAs: "uint8array" when a test, storage layer, or transport wants bytes instead of a browser download.

const writer = new ZipWriter({ outputAs: "uint8array" });
await writer.add({ path: "hello.txt", data: "Hello World\n" });

const zipBytes = await writer.close(); // Uint8Array

Use a Web Worker for large writes

Load the worker plugin only where large async add() calls should prepare and compress entries off the main thread. Host the static worker script yourself so normal CSP and extension rules apply.

See the worker responsiveness demo for a live comparison of main-thread stalls and throughput across the normal writer path, JSZipp worker-backed writing, and other browser compression options.

import { ZipWriter } from "web-jszipp";
import { createWorkerBackend } from "web-jszipp/worker-plugin";

const worker = createWorkerBackend({
  workerSource: () => new Worker(browser.runtime.getURL("vendor/jszipp.worker.mjs"), {
    type: "module"
  }),
  minSize: 512 * 1024
});

try {
  const writer = new ZipWriter({ outputAs: "blob", worker });

  for (const file of input.files) {
    await writer.add({ path: file.webkitRelativePath || file.name, data: file });
  }

  const zipBlob = await writer.close();
} finally {
  worker.terminate();
}

Use the worker plugin with a compat build

Compat pages use the matching compat worker plugin and a classic worker script. Use cr86ff68 for Chrome 86 / Firefox 68 and cr61ff58 for Chrome 61 / Firefox 58.

<script src="vendor/cr86ff68/jszipp.umd.js"></script>
<script src="vendor/cr86ff68/jszipp.worker-plugin.umd.js"></script>
<script>
const worker = JSZippWorkerPlugin.createWorkerBackend({
  workerSource: () => new Worker(browser.runtime.getURL("vendor/cr86ff68/jszipp.worker.js"))
});

async function pack(file) {
  try {
    const writer = new JSZipp.ZipWriter({ outputAs: "blob", worker });
    await writer.add({ path: file.name, data: file });
    return await writer.close();
  } finally {
    worker.terminate();
  }
}
</script>

Read a ZIP file

openZip() is the random-access reader. It exposes archive entries and helpers such as text(), bytes(), arrayBuffer(), and stream().

const zip = await openZip(content, {
  pathMode: "strict",
  maxArchiveSize: 50 * 1024 * 1024,
  maxEntrySize: 10 * 1024 * 1024
});

const text = await zip.get("hello.txt")?.text();
console.log(text); // "Hello World\n"

await zip.close();

Read local files with the File API

A file input gives you File objects. Pass each selected ZIP directly to openZip(), then list the entries.

<input type="file" id="zip-files" multiple accept=".zip" />
<ul id="zip-entries"></ul>

<script type="module">
import { openZip } from "web-jszipp";

const input = document.querySelector("#zip-files");
const list = document.querySelector("#zip-entries");

input.addEventListener("change", async () => {
  list.replaceChildren();

  for (const file of input.files) {
    const started = performance.now();
    const zip = await openZip(file, {
      pathMode: "strict-package",
      maxArchiveSize: 50 * 1024 * 1024,
      maxEntrySize: 10 * 1024 * 1024
    });

    const heading = document.createElement("li");
    heading.textContent = `${file.name} loaded in ${Math.round(performance.now() - started)}ms`;
    list.append(heading);

    for (const entry of zip.entries) {
      const item = document.createElement("li");
      item.textContent = entry.path;
      list.append(item);
    }

    await zip.close();
  }
});
</script>

Read a remote ZIP file

Modern browsers can fetch binary ZIP data directly. Use response.blob() for browser sources or response.arrayBuffer() when raw bytes are more convenient.

const response = await fetch("/archives/content.zip");
if (!response.ok) throw new Error(`Download failed: ${response.status}`);

const zip = await openZip(await response.blob(), {
  pathMode: "strict-package",
  maxArchiveSize: 50 * 1024 * 1024,
  maxEntrySize: 10 * 1024 * 1024
});

const content = await zip.get("content.txt")?.text();
console.log(content);

await zip.close();

Give the user its ZIP file

The browser-native JSZipp path is outputAs: "blob". You do not need a FileSaver dependency unless your app already standardizes on one.

async function saveHelloZip() {
  const writer = new ZipWriter({ outputAs: "blob" });
  await writer.add({ path: "Hello.txt", data: "Hello World\n" });

  const blob = await writer.close();
  const url = URL.createObjectURL(blob);

  try {
    const link = document.createElement("a");
    link.href = url;
    link.download = "example.zip";
    link.click();
  } finally {
    URL.revokeObjectURL(url);
  }
}

Mini app: downloader

This mirrors the JSZip downloader demo: select remote files, fetch them, pack them, and download the result. JSZipp writes each fetched Blob with ZipWriter.add().

<form id="download-form">
  <label><input type="checkbox" data-url="/books/metamorphosis.epub" checked /> Metamorphosis.epub</label>
  <label><input type="checkbox" data-url="/assets/pygments.css" checked /> pygments.css</label>
  <label><input type="checkbox" data-url="/dist/jszipp.mjs" /> jszipp.mjs</label>
  <button type="submit">Pack them</button>
</form>
<progress id="progress" max="100" value="0"></progress>
<p id="result"></p>

<script type="module">
import { ZipWriter } from "web-jszipp";

const form = document.querySelector("#download-form");
const progress = document.querySelector("#progress");
const result = document.querySelector("#result");

form.addEventListener("submit", async (event) => {
  event.preventDefault();
  result.textContent = "";
  progress.value = 0;

  const checked = [...form.querySelectorAll("input:checked")];
  const writer = new ZipWriter({ outputAs: "blob" });

  try {
    for (let i = 0; i < checked.length; i++) {
      const url = checked[i].dataset.url;
      const response = await fetch(url);
      if (!response.ok) throw new Error(`Failed to fetch ${url}`);

      await writer.add({
        path: new URL(url, location.href).pathname.split("/").pop(),
        data: await response.blob()
      });

      progress.value = Math.round(((i + 1) / checked.length) * 100);
    }

    const blob = await writer.close();
    const objectUrl = URL.createObjectURL(blob);
    const link = document.createElement("a");
    link.href = objectUrl;
    link.download = "example.zip";
    link.click();
    URL.revokeObjectURL(objectUrl);

    result.textContent = "done";
  } catch (error) {
    result.textContent = error.message;
  }
});
</script>

Use a stream-shaped ZIP output

ZipTransformStream fits Web Streams pipelines. JSZipp's current writer still prepares each entry as a complete unit, but the archive output can be consumed as a stream.

import { ZipTransformStream } from "web-jszipp";

const zipper = new ZipTransformStream({ level: 6 });
const writer = zipper.writable.getWriter();

const upload = fetch("/upload", {
  method: "POST",
  body: zipper.readable,
  headers: { "Content-Type": "application/zip" }
});

await writer.write({ path: "hello.txt", data: "Hello from a stream-shaped ZIP\n" });
await writer.close();
await upload;
Try it live: the local browser lab in demo/index.html remains the interactive playground for ZIP creation and inspection.