blob-util vs download vs downloadjs vs file-saver vs js-file-download
Client-Side File Generation and Download Strategies in Modern Web Apps
blob-utildownloaddownloadjsfile-saverjs-file-download类似的npm包:

Client-Side File Generation and Download Strategies in Modern Web Apps

These libraries address the challenge of triggering file downloads directly from the browser, a common requirement for exporting reports, saving user-generated content, or handling binary data. file-saver is the industry standard for saving Blob objects, relying on the browser's native saveAs behavior. downloadjs and js-file-download offer lightweight, function-based alternatives that often handle data URI conversion internally. blob-util differs slightly by providing a suite of utility functions to convert between Blobs, Arrays, Strings, and Data URIs, which is often a prerequisite step before downloading. The download package is distinct as it is designed primarily for Node.js environments to fetch and save files to disk, making it less relevant for pure client-side browser architectures unless used in server-side rendering contexts.

npm下载趋势

3 年

GitHub Stars 排名

统计详情

npm包名称
下载量
Stars
大小
Issues
发布时间
License
blob-util0509-38 年前Apache-2.0
download01,300-667 年前MIT
downloadjs02,325-5110 年前MIT
file-saver021,960-2136 年前MIT
js-file-download0919-116 年前MIT

Client-Side File Downloads: Architecture, Compatibility, and Data Handling

Generating and downloading files directly in the browser is a frequent requirement in modern web applications, whether you are exporting user data to CSV, saving a generated PDF report, or allowing users to keep their work locally. While the HTML5 <a download> attribute handles simple cases, complex scenarios involving binary data, dynamic generation, and legacy browser support require specialized tools. The packages blob-util, download, downloadjs, file-saver, and js-file-download each tackle this problem from different angles.

It is critical to distinguish between client-side and server-side intent immediately. The download package is built for Node.js to fetch files to a server disk, whereas the other four are designed for browser environments. Among the browser tools, file-saver is the robust standard, downloadjs and js-file-download offer lightweight simplicity, and blob-util serves as a data preparation utility.

📦 Core Philosophy: Trigger vs. Transformation

The first architectural decision is understanding what problem you are actually solving. Are you trying to trigger the browser's save dialog, or are you struggling to convert your data into a format the browser can download?

file-saver, downloadjs, and js-file-download focus on the trigger. They take data that is already ready (usually a Blob) and force the browser to open the "Save As" dialog. They handle the creation of temporary object URLs and the cleanup of memory.

blob-util focuses on transformation. It does not trigger downloads itself. Instead, it provides reliable methods to convert data between formats (e.g., Base64 to Blob, ArrayBuffer to String). You often use blob-util before calling one of the other libraries.

download focuses on server-side retrieval. It fetches a remote URL and pipes it to a file stream on the server. It is not used to trigger a browser download from client-side JavaScript.

// blob-util: Transforming data (Preparation)
import { base64ToBlob } from 'blob-util';

const base64Data = 'data:image/png;base64,iVBORw0KGgoAAAANS...';
const blob = await base64ToBlob(base64Data, 'image/png');
// Now 'blob' is ready for a downloader library

// file-saver: Triggering the download (Action)
import { saveAs } from 'file-saver';
saveAs(blob, 'image.png');

// downloadjs: Alternative Trigger (Action)
import download from 'downloadjs';
download(blob, 'image.png', 'image/png');

🌐 Browser Compatibility and Legacy Support

When architecting for enterprise environments, you often cannot assume users have the latest version of Chrome or Firefox. The handling of Object URLs and the download attribute varies significantly across older browsers, particularly Internet Explorer 10 and 11.

file-saver is the gold standard for compatibility. It includes specific polyfills and logic to detect Internet Explorer. If the native saveAs method is unavailable, it falls back to using msSaveBlob or msSaveOrOpenBlob, ensuring your application works even on legacy corporate machines.

downloadjs and js-file-download rely more heavily on standard browser behaviors. While they work perfectly in modern evergreen browsers, they may fail silently or require additional polyfills in older environments. They assume the browser can handle URL.createObjectURL and the <a download> attribute natively.

// file-saver: Handles IE10/11 internally
import { saveAs } from 'file-saver';

// Works in Chrome, Firefox, Safari, AND Internet Explorer
const blob = new Blob(['Hello World'], { type: 'text/plain;charset=utf-8' });
saveAs(blob, 'hello.txt'); 
// Internally checks: if (navigator.msSaveOrOpenBlob) { ... }

// downloadjs: Relies on modern standards
import download from 'downloadjs';

// May require polyfills for IE if createObjectURL is missing
download('Hello World', 'hello.txt', 'text/plain');

🛠️ Data Input Flexibility

Real-world data rarely arrives as a perfect Blob object. You might have a JSON object, a raw string, a Data URI, or an ArrayBuffer. Different libraries accept different input types, which affects how much preprocessing code you need to write.

downloadjs is highly flexible regarding input types. It accepts strings, Blobs, Arrays, and Data URIs directly. It performs internal checks to determine the content type, reducing the boilerplate code you need to write.

js-file-download is similar but slightly more opinionated, often expecting strings or Blobs. It is very effective for text-based downloads like CSVs or logs.

file-saver is strictly typed towards Blob objects. If you have a string or a JSON object, you must manually convert it to a Blob before passing it to saveAs. This adds a step but ensures explicit control over MIME types.

blob-util shines here by providing the missing conversion steps for file-saver.

// downloadjs: Accepts raw strings and auto-detects
import download from 'downloadjs';

// Pass a string directly; library handles Blob creation internally
download('ID,Name,Value\n1,Item A,100', 'report.csv', 'text/csv');

// file-saver: Requires explicit Blob creation
import { saveAs } from 'file-saver';

const csvContent = 'ID,Name,Value\n1,Item A,100';
// Must manually create Blob with correct MIME type
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
saveAs(blob, 'report.csv');

// blob-util: Helping with complex conversions
import { arrayBufferToBlob } from 'blob-util';

// If you have an ArrayBuffer from a WebSocket or Canvas
const buffer = await getBinaryData(); 
const blob = await arrayBufferToBlob(buffer, 'application/octet-stream');
saveAs(blob, 'binary.dat'); // Used with file-saver

⚠️ Deprecation and Maintenance Status

Architectural decisions must account for the long-term viability of dependencies. Using unmaintained libraries introduces security risks and technical debt.

The download package (intended for Node.js) has historically faced maintenance issues and is often considered deprecated or unstable for modern Node.js workflows. Modern Node.js applications should prefer native fetch combined with fs.createWriteStream or libraries like node-fetch and stream-saver for better control and performance. It should not be used in new projects unless you have a specific legacy constraint.

file-saver remains actively maintained and is the reference implementation for the W3C FileSaver specification. It is safe for long-term use.

downloadjs and js-file-download are stable, lightweight utilities that rarely require updates because the underlying browser APIs they wrap are stable. They are safe to use.

blob-util is a utility library that is also stable, as the Blob API specifications are mature.

// AVOID: Using 'download' package in new Node.js projects
// Instead, use native Node.js streams:
import fs from 'fs';
import https from 'https';

const file = fs.createWriteStream('image.png');
https.get('https://example.com/image.png', (response) => {
  response.pipe(file);
});

// PREFERRED: Using file-saver for client-side stability
import { saveAs } from 'file-saver';
// Reliable, standard-compliant, and maintained

🚀 Performance and Memory Management

When dealing with large files (e.g., exporting a 50MB dataset), memory management becomes critical. Creating Object URLs (URL.createObjectURL) ties up memory until explicitly revoked.

file-saver attempts to manage this automatically but gives developers the option to manually revoke URLs if needed for massive files. It is optimized to handle large Blobs without blocking the main thread excessively.

downloadjs and js-file-download create temporary anchor tags and Object URLs. In very long-running single-page applications (SPAs), if you trigger thousands of downloads in a session, you should be aware of potential memory leaks if the library does not revoke URLs aggressively. However, for typical user interactions (one or two exports per session), this is negligible.

blob-util operations are synchronous or promise-based conversions that happen in memory. Converting massive Base64 strings to Blobs can be CPU intensive and may cause temporary UI jank. It is recommended to perform heavy blob-util conversions inside a Web Worker if the data size exceeds a few megabytes.

// file-saver: Standard usage
import { saveAs } from 'file-saver';
const blob = generateLargeReport();
saveAs(blob, 'report.pdf');
// Library handles URL cleanup after download initiates

// blob-util: Potential performance bottleneck on main thread
import { base64ToBlob } from 'blob-util';

// For huge strings, move this to a Web Worker to prevent UI freeze
const hugeBase64 = getHugeString(); 
// const blob = await base64ToBlob(hugeBase64, 'application/pdf'); 
// ^ This blocks the thread if 'hugeBase64' is > 10MB

📊 Summary of Use Cases

ScenarioRecommended PackageWhy?
Enterprise App with IE Supportfile-saverOnly library with robust IE10/11 fallbacks.
Simple CSV/Text ExportdownloadjsMinimal code, accepts strings directly, lightweight.
Data Conversion (Base64 ↔ Blob)blob-utilSpecialized utilities for format transformation.
Server-Side File FetchingNative Node Streamsdownload package is deprecated/unreliable; use native fs.
Minimalist Bundlejs-file-downloadTiny footprint for simple text/blob downloads.

💡 Final Architectural Recommendation

For most modern frontend architectures, file-saver remains the safest default choice due to its strict adherence to standards and legacy support. It removes guesswork from MIME types and browser quirks.

However, if you are building a modern, greenfield application where legacy browser support is not a requirement, downloadjs offers a cleaner, more ergonomic API that reduces boilerplate code. Use blob-util as a companion tool whenever your data source is not already a Blob (e.g., converting Canvas images or Base64 API responses).

Finally, strictly avoid the download package for client-side logic. Its domain is the server, and even there, native Node.js streams are now superior. By selecting the right tool for the specific layer (data transformation vs. download triggering), you ensure a responsive, compatible, and maintainable file handling system.

如何选择: blob-util vs download vs downloadjs vs file-saver vs js-file-download

  • blob-util:

    Choose blob-util when your primary challenge is data transformation rather than the download trigger itself. It is ideal if you need to convert complex data structures (like Base64 strings or ArrayBuffers) into Blob objects before passing them to a downloader. It acts as a reliable utility belt for preparing data formats but does not initiate the browser download dialog on its own.

  • download:

    Avoid download for client-side browser applications; it is built for Node.js environments to fetch remote URLs and write them to the server's file system. Only select this package if you are building a server-side script, a CLI tool, or an API endpoint that needs to retrieve and store files on the backend before serving them to the client.

  • downloadjs:

    Select downloadjs for a lightweight, zero-dependency solution when you need a simple function to trigger downloads from various data types (Blobs, Strings, Data URIs). It is an excellent choice for modern projects where you want to avoid the heavier API surface of file-saver and prefer a straightforward function call that handles MIME type detection automatically.

  • file-saver:

    Opt for file-saver when you require maximum cross-browser compatibility and adherence to the W3C saveAs FileSaver specification. It is the safest choice for enterprise applications supporting legacy browsers (like older versions of Internet Explorer) or when you need robust handling of large Blob objects that might crash simpler implementations.

  • js-file-download:

    Pick js-file-download when you need a minimalistic wrapper that simplifies the creation of anchor tags for downloading text or binary data. It is suitable for projects that prioritize small bundle size and simple use cases, such as downloading CSV exports or text logs, without needing the extensive feature set of file-saver.

blob-util的README

blob-util Build Status TypeScript

blob-util is a Blob library for busy people.

It offers a small set of cross-browser utilities for translating Blobs to and from different formats:

  • <img/> tags
  • base 64 strings
  • binary strings
  • ArrayBuffers
  • data URLs
  • canvas

It's also a good pairing with the attachment API in PouchDB.

Note: this is a browser library. For Node.js, see Buffers.

Topics:

Install

Via npm:

npm install blob-util

ES modules are supported:

import { canvasToBlob } from 'blob-util'
canvasToBlob(canvas, 'image/png').then(/* ... */)

Or as a script tag:

<script src="https://unpkg.com/blob-util/dist/blob-util.min.js"></script>

Then it's available as a global blobUtil object:

blobUtil.canvasToBlob(canvas, 'image/png').then(/* ... */)

Browser support

As of v2.0.0, a built-in Promise polyfill is no longer provided. Assuming you provide a Promise polyfill, the supported browsers are:

  • Firefox
  • Chrome
  • Edge
  • IE 10+
  • Safari 6+
  • iOS 6+
  • Android 4+
  • Any browser with either Blob or the older BlobBuilder; see caniuse for details.

Tutorial

Blobs (binary large objects) are the modern way of working with binary data in the browser. The browser support is very good.

Once you have a Blob, you can make it available offline by storing it in IndexedDB, PouchDB, LocalForage, or other in-browser databases. So it's the perfect format for working with offline images, sound, and video.

A File is also a Blob. So if you have an <input type="file"> in your page, you can let your users upload any file and then work with it as a Blob.

Example

Here's Kirby. He's a famous little Blob.

Kirby

So let's fulfill his destiny, and convert him to a real Blob object.

var img = document.getElementById('kirby');

blobUtil.imgSrcToBlob(img.src).then(function (blob) {
  // ladies and gents, we have a blob
}).catch(function (err) {
  // image failed to load
});

(Don't worry, this won't download the image twice, because browsers are smart.)

Now that we have a Blob, we can convert it to a URL and use that as the source for another <img/> tag:

var blobURL = blobUtil.createObjectURL(blob);

var newImg = document.createElement('img');
newImg.src = blobURL;

document.body.appendChild(newImg);

So now we have two Kirbys - one with a normal URL, and the other with a blob URL. You can try this out yourself in the blob-util playground. Super fun!

API

Index

Functions


Functions

arrayBufferToBinaryString

▸ arrayBufferToBinaryString(buffer: ArrayBuffer): string

Convert an ArrayBuffer to a binary string.

Example:

var myString = blobUtil.arrayBufferToBinaryString(arrayBuff)

Parameters:

ParamTypeDescription
bufferArrayBufferarray buffer

Returns: string binary string


arrayBufferToBlob

▸ arrayBufferToBlob(buffer: ArrayBuffer, type?: string): Blob

Convert an ArrayBuffer to a Blob.

Example:

var blob = blobUtil.arrayBufferToBlob(arrayBuff, 'audio/mpeg');

Parameters:

ParamTypeDescription
bufferArrayBuffer-
Optional typestringthe content type (optional)

Returns: Blob Blob


base64StringToBlob

▸ base64StringToBlob(base64: string, type?: string): Blob

Convert a base64-encoded string to a Blob.

Example:

var blob = blobUtil.base64StringToBlob(base64String);

Parameters:

ParamTypeDescription
base64stringbase64-encoded string
Optional typestringthe content type (optional)

Returns: Blob Blob


binaryStringToArrayBuffer

▸ binaryStringToArrayBuffer(binary: string): ArrayBuffer

Convert a binary string to an ArrayBuffer.

var myBuffer = blobUtil.binaryStringToArrayBuffer(binaryString)

Parameters:

ParamTypeDescription
binarystringbinary string

Returns: ArrayBuffer array buffer


binaryStringToBlob

▸ binaryStringToBlob(binary: string, type?: string): Blob

Convert a binary string to a Blob.

Example:

var blob = blobUtil.binaryStringToBlob(binaryString);

Parameters:

ParamTypeDescription
binarystringbinary string
Optional typestringthe content type (optional)

Returns: Blob Blob


blobToArrayBuffer

▸ blobToArrayBuffer(blob: Blob): Promise<ArrayBuffer>

Convert a Blob to an ArrayBuffer.

Example:

blobUtil.blobToArrayBuffer(blob).then(function (arrayBuff) {
  // success
}).catch(function (err) {
  // error
});

Parameters:

ParamTypeDescription
blobBlob-

Returns: Promise<ArrayBuffer> Promise that resolves with the ArrayBuffer


blobToBase64String

▸ blobToBase64String(blob: Blob): Promise<string>

Convert a Blob to a binary string.

Example:

blobUtil.blobToBase64String(blob).then(function (base64String) {
  // success
}).catch(function (err) {
  // error
});

Parameters:

ParamTypeDescription
blobBlob-

Returns: Promise<string> Promise that resolves with the binary string


blobToBinaryString

▸ blobToBinaryString(blob: Blob): Promise<string>

Convert a Blob to a binary string.

Example:

blobUtil.blobToBinaryString(blob).then(function (binaryString) {
  // success
}).catch(function (err) {
  // error
});

Parameters:

ParamTypeDescription
blobBlob-

Returns: Promise<string> Promise that resolves with the binary string


blobToDataURL

▸ blobToDataURL(blob: Blob): Promise<string>

Convert a Blob to a data URL string (e.g. 'data:image/png;base64,iVBORw0KG...').

Example:

var dataURL = blobUtil.blobToDataURL(blob);

Parameters:

ParamTypeDescription
blobBlob-

Returns: Promise<string> Promise that resolves with the data URL string


canvasToBlob

▸ canvasToBlob(canvas: HTMLCanvasElement, type?: string, quality?: number): Promise<Blob>

Convert a canvas to a Blob.

Examples:

blobUtil.canvasToBlob(canvas).then(function (blob) {
  // success
}).catch(function (err) {
  // error
});

Most browsers support converting a canvas to both 'image/png' and 'image/jpeg'. You may also want to try 'image/webp', which will work in some browsers like Chrome (and in other browsers, will just fall back to 'image/png'):

blobUtil.canvasToBlob(canvas, 'image/webp').then(function (blob) {
  // success
}).catch(function (err) {
  // error
});

Parameters:

ParamTypeDescription
canvasHTMLCanvasElementHTMLCanvasElement
Optional typestringthe content type (optional, defaults to 'image/png')
Optional qualitynumbera number between 0 and 1 indicating image quality if the requested type is 'image/jpeg' or 'image/webp'

Returns: Promise<Blob> Promise that resolves with the Blob


createBlob

▸ createBlob(parts: Array<any>, properties?: * BlobPropertyBag | string*): Blob

Shim for new Blob() to support older browsers that use the deprecated BlobBuilder API.

Example:

var myBlob = blobUtil.createBlob(['hello world'], {type: 'text/plain'});

Parameters:

ParamTypeDescription
partsArray<any>content of the Blob
Optional propertiesBlobPropertyBag | stringusually {type: myContentType}, you can also pass a string for the content type

Returns: Blob Blob


createObjectURL

▸ createObjectURL(blob: Blob): string

Shim for URL.createObjectURL() to support browsers that only have the prefixed webkitURL (e.g. Android <4.4).

Example:

var myUrl = blobUtil.createObjectURL(blob);

Parameters:

ParamTypeDescription
blobBlob-

Returns: string url


dataURLToBlob

▸ dataURLToBlob(dataURL: string): Blob

Convert a data URL string (e.g. 'data:image/png;base64,iVBORw0KG...') to a Blob.

Example:

var blob = blobUtil.dataURLToBlob(dataURL);

Parameters:

ParamTypeDescription
dataURLstringdataURL-encoded string

Returns: Blob Blob


imgSrcToBlob

▸ imgSrcToBlob(src: string, type?: string, crossOrigin?: string, quality?: number): Promise<Blob>

Convert an image's src URL to a Blob by loading the image and painting it to a canvas.

Note: this will coerce the image to the desired content type, and it will only paint the first frame of an animated GIF.

Examples:

blobUtil.imgSrcToBlob('http://mysite.com/img.png').then(function (blob) {
  // success
}).catch(function (err) {
  // error
});
blobUtil.imgSrcToBlob('http://some-other-site.com/img.jpg', 'image/jpeg',
                         'Anonymous', 1.0).then(function (blob) {
  // success
}).catch(function (err) {
  // error
});

Parameters:

ParamTypeDescription
srcstringimage src
Optional typestringthe content type (optional, defaults to 'image/png')
Optional crossOriginstringfor CORS-enabled images, set this to 'Anonymous' to avoid "tainted canvas" errors
Optional qualitynumbera number between 0 and 1 indicating image quality if the requested type is 'image/jpeg' or 'image/webp'

Returns: Promise<Blob> Promise that resolves with the Blob


imgSrcToDataURL

▸ imgSrcToDataURL(src: string, type?: string, crossOrigin?: string, quality?: number): Promise<string>

Convert an image's src URL to a data URL by loading the image and painting it to a canvas.

Note: this will coerce the image to the desired content type, and it will only paint the first frame of an animated GIF.

Examples:

blobUtil.imgSrcToDataURL('http://mysite.com/img.png').then(function (dataURL) {
  // success
}).catch(function (err) {
  // error
});
blobUtil.imgSrcToDataURL('http://some-other-site.com/img.jpg', 'image/jpeg',
                         'Anonymous', 1.0).then(function (dataURL) {
  // success
}).catch(function (err) {
  // error
});

Parameters:

ParamTypeDescription
srcstringimage src
Optional typestringthe content type (optional, defaults to 'image/png')
Optional crossOriginstringfor CORS-enabled images, set this to 'Anonymous' to avoid "tainted canvas" errors
Optional qualitynumbera number between 0 and 1 indicating image quality if the requested type is 'image/jpeg' or 'image/webp'

Returns: Promise<string> Promise that resolves with the data URL string


revokeObjectURL

▸ revokeObjectURL(url: string): void

Shim for URL.revokeObjectURL() to support browsers that only have the prefixed webkitURL (e.g. Android <4.4).

Example:

blobUtil.revokeObjectURL(myUrl);

Parameters:

ParamTypeDescription
urlstring

Returns: void


Credits

Thanks to the rest of the PouchDB team for figuring most of this crazy stuff out.

Building the library

npm install
npm run build

Testing the library

npm install

Then to test in the browser using Saucelabs:

npm test

Or to test locally in your browser of choice:

npm run test-local

To build the API docs and insert them in the README:

npm run doc