JSZip - Documentation

What is JSZip?

JSZip is a JavaScript library for creating, reading, and manipulating zip files in the browser and Node.js. It allows you to add files to a zip archive, extract files from a zip archive, and perform other zip-related operations entirely client-side, without requiring server-side interaction for basic zip file manipulation. JSZip handles the complexities of the ZIP file format, providing a simple and consistent API for developers to work with.

Why use JSZip?

JSZip offers several compelling reasons for its use in your projects:

Setting up JSZip: Installation and Basic Usage

Node.js:

To use JSZip in a Node.js project, install it using npm or yarn:

npm install jszip
# or
yarn add jszip

Then, you can include it in your code:

const JSZip = require('jszip');

// ... your JSZip code ...

Browser:

You can include JSZip in your browser project via a <script> tag from a CDN, like jsDelivr:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>

or by downloading the library and including it locally. Then, the JSZip object will be available globally.

A basic example of creating a zip file in both environments:

const zip = new JSZip();
zip.file("hello.txt", "Hello, world!");
zip.generateAsync({type:"blob"})
  .then(function(content) {
    // see FileSaver.js
    saveAs(content, "example.zip");
  });

Remember to include a library like FileSaver.js for saving the generated zip file in the browser.

JSZip and Browser Compatibility

JSZip is designed to work across a wide range of modern browsers. While it strives for broad compatibility, older or less commonly used browsers might exhibit limitations. It’s generally recommended to target evergreen browsers (those that auto-update) to ensure consistent functionality. For optimal performance, it is important to consider using features supported by modern JavaScript implementations. Refer to the JSZip documentation and release notes for detailed information on supported browsers and any potential compatibility issues or known limitations with specific browser versions.

Core Functionality: Creating and Manipulating Zip Files

Creating a new Zip file

Creating a new zip file using JSZip is straightforward. You instantiate a new JSZip object, which represents an empty zip archive. Subsequently, you add files and folders to this object before generating the final zip file.

const JSZip = require('jszip'); // or import JSZip from 'jszip'; for ES modules

const zip = new JSZip();
// ... add files and folders to the 'zip' object ...

Adding files to a Zip archive

Files are added using the file() method. This method takes the file name (including path if needed for subdirectories) and the file content as arguments. The content can be a string, a Uint8Array, or a Blob.

zip.file("hello.txt", "Hello, world!");
zip.file("my_image.jpg", new Uint8Array([ /* your image data */ ]));
zip.file("path/to/file.json", JSON.stringify({data: "some data"}));

Adding folders to a Zip archive

JSZip automatically handles folder creation. You don’t explicitly create folders; simply add files with paths that include directory separators (“/” or “\”).

zip.file("images/image1.png", "...");
zip.file("images/image2.png", "...");
zip.file("documents/report.pdf", "...");

This will create the “images” and “documents” folders within the zip archive.

Reading files from a Zip archive

You can access individual files within the archive using the file() method (to get the file object) or forEach() to iterate through the files. The file content can then be accessed using the async methods.

zip.file("hello.txt").async("string").then(function (content) {
    console.log(content); // Outputs "Hello, world!"
});

zip.forEach(function (relativePath, zipEntry) {
    console.log(relativePath);
    zipEntry.async("string").then(function(content){
        console.log(content);
    });
});

Removing files from a Zip archive

Remove files using the remove() method.

zip.remove("hello.txt");
zip.remove("images/image1.png");

Updating files in a Zip archive

Updating a file simply involves adding a file with the same name. The previous version will be overwritten.

zip.file("hello.txt", "New Hello, world!");

File Metadata (name, comment, etc.)

JSZip allows you to set various metadata properties for files within the archive, such as comments. This is done through the zipEntry object obtained from zip.file().

const file = zip.file("my_file.txt", "Some text");
file.comment = "This is a comment about my_file.txt";
file.name = "updated_file_name.txt" //This will change file name

// Accessing metadata
console.log(file.comment); // Access the comment
console.log(file.name); // Access the filename

Handling large files

For large files, it’s crucial to use asynchronous methods to avoid blocking the main thread. JSZip’s asynchronous methods (those ending in Async) are designed for this purpose. Instead of directly accessing the file content, you should use .async("string"), .async("uint8array"), or .async("blob") to read files asynchronously. Also, consider using streaming options when generating the zip file to improve memory management. Chunking the large file into smaller parts before adding to the archive might also be beneficial. Refer to the JSZip documentation for advanced options concerning stream handling and large files.

zip.file("largefile.txt", new ReadableStream()).generateAsync({type: 'blob', streamFiles:true}).then(function(content){
    // handle the blob
})

Remember to replace ReadableStream with your actual large file streaming mechanism. The streamFiles: true option is crucial for handling large files efficiently.

Advanced Techniques

Working with Zip streams

For optimal performance with large files, working directly with streams is essential. JSZip supports streaming both during file addition and zip archive generation. Instead of loading the entire file content into memory, you can provide a stream (like a ReadableStream in browsers or a Node.js stream) as the file content. This is particularly beneficial when dealing with files larger than available memory. The generateAsync method allows configuring stream-based generation.

// Example using a Node.js stream (adapt for browser ReadableStream)
const fs = require('node:fs');
const zip = new JSZip();
const readStream = fs.createReadStream('largefile.txt');

zip.file('largefile.txt', readStream);

zip.generateAsync({ type: 'nodebuffer', streamFiles: true })
  .then(function (content) {
    // Handle the generated zip file as a Buffer
  });

Asynchronous operations

JSZip’s core functionality is built around asynchronous operations. Methods like generateAsync(), loadAsync(), and file access methods with .async() ensure that long-running tasks don’t block the main thread. This is crucial for responsiveness in browser applications and prevents performance bottlenecks in Node.js. Always prefer asynchronous methods when dealing with potentially large zip files or numerous files.

Using Promises

JSZip’s asynchronous methods return Promises. This allows you to use standard Promise chaining and error handling techniques for a clean and efficient approach to asynchronous programming.

zip.generateAsync({ type: 'blob' })
  .then(function (content) {
    // Success: 'content' is the generated zip file as a Blob
    saveAs(content, "myzip.zip"); // Requires FileSaver.js
  })
  .catch(function (error) {
    // Error handling
    console.error("Error generating zip:", error);
  });

Error Handling

Proper error handling is crucial when working with JSZip. Utilize .catch() blocks to handle potential errors during zip file generation, loading, or file access. JSZip typically throws errors for issues like invalid zip files, missing files, or incorrect input data. These errors provide helpful information for debugging.

zip.loadAsync(fileContent)
  .then(function (zip) {
    // Zip file loaded successfully
  })
  .catch(function (error) {
    console.error("Error loading zip file:", error);
  });

Customizing Compression Levels

JSZip allows you to control the compression level for individual files or the entire archive. Higher compression levels (e.g., DEFLATE with a higher compression level) result in smaller zip files but require more processing time. Lower levels are faster but result in larger files.

zip.file("compressedFile.txt", "My text", { compression: 'DEFLATE', compressionOptions: { level: 9 } }); // High compression
zip.file("lessCompressedFile.txt", "My text", { compression: 'DEFLATE', compressionOptions: { level: 1 } }); // Low compression

zip.generateAsync({ type: 'blob', compression: 'DEFLATE', compressionOptions: { level: 6 } }) //default compression for all files
    .then(...)
    .catch(...);

Using different compression methods

Besides DEFLATE, JSZip supports other compression methods, though DEFLATE is the most common and generally recommended. The availability and performance of alternative methods might vary depending on the browser or environment. Check the JSZip documentation for details on supported compression methods.

Handling encrypted zip files

JSZip’s core functionality does not directly support creating or decrypting encrypted zip files. Encryption requires additional libraries and often involves more complex cryptography. Note that handling encrypted ZIP files introduces significant security considerations, and improper handling can lead to vulnerabilities.

Integration with other libraries

JSZip can be readily integrated with other JavaScript libraries. For example, it works well with libraries for handling file uploads/downloads (like FileSaver.js and Dropzone.js), image manipulation, or other data processing tasks. The flexibility of JSZip’s API (accepting various data types) makes it easy to incorporate it into complex workflows.

JSZip and other Technologies

JSZip with Node.js

JSZip works seamlessly within Node.js environments. Installation is via npm or yarn (as described in the basic usage section). The API remains consistent, but you’ll typically work with buffers (Buffer) instead of Blob objects for file I/O. Node.js’s file system access capabilities can be leveraged for reading and writing zip files directly to disk.

const JSZip = require('jszip');
const fs = require('node:fs/promises'); //For Asynchronous file operations

async function zipFiles(files){
    const zip = new JSZip();
    for (const file of files){
        const data = await fs.readFile(file.path);
        zip.file(file.name, data);
    }
    const zipBuffer = await zip.generateAsync({type:"nodebuffer"});
    await fs.writeFile("myZipFile.zip",zipBuffer);
}

JSZip with Web Workers

To improve the responsiveness of your web application when dealing with potentially long-running zip operations (especially with large files), offload the work to Web Workers. This prevents blocking the main thread. Create a Web Worker that handles the JSZip operations and communicate with it via messages to send and receive data.

// main thread
const worker = new Worker('worker.js');
worker.postMessage({ action: 'generateZip', files: files });
worker.onmessage = function(e) {
    // Handle zip file received from worker
};

// worker.js
onmessage = function(e) {
    const { action, files } = e.data;
    if (action === 'generateZip') {
        //Use JSZip here to generate the zip file asynchronously
        // ... JSZip code ...
        postMessage({ action: 'zipGenerated', zip: zipBlob }); // send the generated zip back to the main thread
    }
};

JSZip with React

Integrate JSZip into React applications by importing it into your component and using it within lifecycle methods or functional components. For large zip operations, consider using asynchronous operations and managing loading states to provide a smooth user experience.

import React, { useState } from 'react';
import JSZip from 'jszip';

function MyComponent() {
  const [zipBlob, setZipBlob] = useState(null);

  const generateZip = async () => {
    const zip = new JSZip();
    // ... add files to the zip ...
    const blob = await zip.generateAsync({ type: 'blob' });
    setZipBlob(blob);
  };

  return (
    <div>
      <button onClick={generateZip}>Generate Zip</button>
      {zipBlob && <a href={URL.createObjectURL(zipBlob)} download="myzip.zip">Download</a>}
    </div>
  );
}

JSZip with Angular

Similar to React, integrate JSZip into Angular applications by importing it into your service or component and using it within methods. Leverage Angular’s dependency injection and RxJS observables to handle asynchronous operations effectively.

JSZip with Vue

In Vue applications, you can use JSZip within your components’ methods. Utilize Vue’s reactivity system to update the UI as needed during asynchronous zip operations.

JSZip and File APIs

JSZip works well with browser File APIs. You can use the File API to select files from the user’s computer, read their contents, add them to a zip archive, and handle the generated zip file (using Blob objects).

//example of handling file selection.
const input = document.createElement('input');
input.type = 'file';
input.multiple = true;
input.addEventListener('change', async (e) => {
    const files = e.target.files;
    //Use JSZip to create a zip file with the selected files.
});

JSZip and server-side technologies

While JSZip primarily operates client-side, it can be used in conjunction with server-side technologies. The client-side can generate a zip file using JSZip and then send it to the server for storage or further processing, or the server can send the zip file to the client for download after server side generation. Node.js, for example, can use JSZip for server-side zip file manipulation. However, for large-scale zip processing on the server, more performant server-side libraries might be preferable.

Best Practices and Optimization

Optimizing for performance

Optimizing JSZip usage for performance involves several key strategies:

Memory management

Efficient memory management is crucial, particularly when working with large zip files. The core strategies for this are:

Security considerations

Security is paramount, especially when handling user-uploaded files or sensitive data within zip archives:

Code examples and best practices

Example of best practices using async/await and streaming:

const JSZip = require('jszip');
const fs = require('node:fs/promises');

async function createZip(files) {
  const zip = new JSZip();
  for (const file of files) {
    const data = await fs.readFile(file.path);
    zip.file(file.name, data);
  }

  const zipBuffer = await zip.generateAsync({ type: 'nodebuffer', streamFiles: true });
  await fs.writeFile('myzip.zip', zipBuffer);
}

This example demonstrates proper async/await usage and streaming for efficient zip file generation in Node.js. Adapt the streaming to use ReadableStream in browsers. Remember to always handle potential errors using try…catch blocks within your asynchronous functions. Always validate user input thoroughly and never trust user-supplied data without thorough sanitization and validation.

API Reference

This section provides a concise overview of the core JSZip API. For complete and up-to-date details, refer to the official JSZip documentation. Note that specific method signatures and available options might vary across JSZip versions.

JSZip Class

The JSZip class is the primary entry point for creating and manipulating zip archives.

ZipFile Class

The ZipFile class (or similar, depending on the JSZip version) represents a single file within the archive. It’s obtained using zip.file(name). The properties and methods available depend on the JSZip version. Key properties typically include:

ZipObject Class

This class (or a similar representation) may be available in newer JSZip versions, offering a more structured way to interact with both files and folders in the archive. Check the official JSZip documentation for specific details and properties available for your JSZip version.

Utility functions

JSZip might provide utility functions (the availability depends on the version). These are helper functions not directly related to creating or modifying zip files but can be useful in related tasks. Refer to the official documentation for the complete list. These may include functions to work with data types such as Blob and Uint8Array.

Important Note: This is a simplified overview. Consult the official JSZip documentation for the most current and detailed API reference, including specific method signatures, options, and error handling. The API might evolve across versions, so always verify against the current version you are using.

Troubleshooting

Common errors and solutions

This section covers some common issues encountered when using JSZip and suggests troubleshooting steps. Always refer to the console logs and error messages for specific details.

Debugging tips

Where to find help

Remember to always check the error messages provided by JSZip. They are often very helpful in identifying the source of the problem. Provide sufficient context when asking for help (code snippet, error message, steps to reproduce).