Compressor.js
Compressor.js is a client-side JavaScript image compression library that leverages the browser's native `HTMLCanvasElement.toBlob()` method for its core functionality. It performs lossy, asynchronous compression, meaning results can vary slightly across different web browsers and privacy settings. Primarily designed for pre-compressing images on the client before upload, it provides a straightforward API for handling `File` or `Blob` objects. The current stable version is 1.3.0, and the project appears actively maintained with a steady cadence of minor updates addressing bug fixes and introducing new options. Its key differentiator is its reliance on native browser APIs, simplifying its footprint but also making its compression effects browser-dependent. It ships with TypeScript types.
Common errors
-
The operation is insecure
cause This error can occur when canvas operations (like `toBlob()`) are attempted on images loaded from different origins without appropriate Cross-Origin Resource Sharing (CORS) headers. While some internal cases were fixed in v1.0.6, it can still manifest with external image sources.fixEnsure that images loaded from external domains are served with proper CORS headers (e.g., `Access-Control-Allow-Origin: *` or specific domains). For locally generated or user-provided files, this error is less common but can indicate browser security restrictions. -
TypeError: Cannot read properties of undefined (reading 'files')
cause This error typically indicates that the DOM element for the file input was not found or was accessed before the HTML document was fully loaded.fixEnsure your JavaScript code executes after the DOM is ready. Place your script tag at the end of the `<body>` or wrap your initialization code in a `DOMContentLoaded` event listener (e.g., `document.addEventListener('DOMContentLoaded', () => { ... });`). -
TypeError: Cannot set properties of undefined (setting 'quality')
cause This error usually occurs if `new Compressor()` is called with an invalid `file` argument (e.g., `null` or `undefined`) or if the `Compressor` class is not correctly instantiated using the `new` keyword.fixVerify that the `file` argument passed to `new Compressor(file, options)` is a valid `File` or `Blob` object, and always instantiate the class with `new Compressor(...)`.
Warnings
- gotcha Compressor.js relies on the browser's native `HTMLCanvasElement.toBlob()` method, which performs lossy compression. The final image quality and compression efficiency can vary significantly across different web browsers and their implementations.
- gotcha The compression process is asynchronous, meaning the compressed image `result` is only accessible within the `success` callback function. Attempting to access `result` outside this callback will lead to undefined behavior or errors.
- gotcha In Firefox, with `privacy.resistFingerprinting` mode enabled, `canvas.getContext('2d').getImageData()` might be unavailable. In such scenarios, Compressor.js (v1.3.0 and later) will output the original image instead of attempting compression.
- gotcha By default (`strict: true`), the library will output the original image if the compressed image's size is larger than the original, unless specific options like `retainExif`, a `mimeType` change, or explicit `width`/`height` constraints are set.
- breaking Prior to version 1.1.1, Compressor.js could encounter loading errors when used in Node.js environments due to incompatible syntax in its bundled files.
Install
-
npm install compressorjs -
yarn add compressorjs -
pnpm add compressorjs
Imports
- Compressor
import { Compressor } from 'compressorjs';import Compressor from 'compressorjs';
- Compressor
const Compressor = require('compressorjs');const Compressor = require('compressorjs/dist/compressor.common.js'); - Compressor.setDefaults
import { setDefaults } from 'compressorjs';import Compressor from 'compressorjs'; Compressor.setDefaults({ quality: 0.8 });
Quickstart
import Compressor from 'compressorjs';
// Create a dummy file input for demonstration purposes
const inputElement = document.createElement('input');
inputElement.setAttribute('type', 'file');
inputElement.setAttribute('id', 'fileInput');
inputElement.setAttribute('accept', 'image/*');
document.body.appendChild(inputElement);
document.getElementById('fileInput')?.addEventListener('change', (e) => {
const target = e.target as HTMLInputElement;
const file = target.files?.[0];
if (!file) {
console.log('No file selected.');
return;
}
new Compressor(file, {
quality: 0.6,
maxWidth: 800,
maxHeight: 600,
// Output the original image instead of the compressed one if the compressed size is larger.
strict: true,
success(result) {
console.log('Compression successful! Compressed file:', result);
// The 'result' is a File object (or Blob in older versions).
// You can now upload this 'result' to your server.
const formData = new FormData();
formData.append('compressedImage', result, result.name);
// Example of what you might do next (e.g., using fetch or axios):
// fetch('/path/to/upload', { method: 'POST', body: formData })
// .then(response => console.log('Upload success', response))
// .catch(error => console.error('Upload error', error));
const reader = new FileReader();
reader.onload = (event) => {
const img = document.createElement('img');
img.src = event.target?.result as string;
img.style.maxWidth = '200px';
document.body.appendChild(img);
console.log('Displaying compressed image preview.');
};
reader.readAsDataURL(result);
},
error(err) {
console.error('Compression error:', err.message);
},
});
});