Node.js Readable to Web ReadableStream Conversion Utility
node-readable-to-web-readable-stream is a focused utility library designed to bridge the gap between Node.js `stream.Readable` and the Web API `ReadableStream`. It provides functions to convert Node.js readable streams into either byte-mode (BYOB-compliant) or default-mode WHATWG ReadableStreams, enabling seamless integration with web-native streaming APIs. The current stable version is `0.4.2`, with releases occurring relatively frequently to address bug fixes and introduce enhancements, such as improved backpressure mechanisms and default stream support. Key differentiators include its explicit support for BYOB readers, robust backpressure handling, and cross-platform compatibility across Node.js (>=18), Bun (>=1.2), and modern web browsers. It is distributed as an ECMAScript Module (ESM).
Common errors
-
TypeError: makeByteReadableStreamFromNodeReadable is not a function
cause Attempting to `require()` the module in a Node.js version older than 22, or in a CommonJS context where ESM imports are not correctly transpiled or handled.fixEnsure your project is configured for ESM (e.g., `"type": "module"` in `package.json`) and use `import { makeByteReadableStreamFromNodeReadable } from 'node-readable-to-web-readable-stream';`. If using Node.js < 22, you cannot reliably use `require()` for this package. -
Web ReadableStream stops emitting data unexpectedly or seems to freeze.
cause This is often a symptom of the stream hanging bug fixed in earlier versions, where the converted stream would not properly signal completion or handle cancellation.fixUpgrade the package to version `0.4.1` or newer. This version specifically addressed issues causing converted byte ReadableStreams to hang.
Warnings
- gotcha This package is an ECMAScript Module (ESM). While it can be loaded with `require()` in Node.js, this functionality is officially supported only for Node.js versions 22 and higher. For older Node.js versions or mixed CJS/ESM projects, direct `import` statements are required.
- gotcha Versions prior to `0.4.1` contained a bug that could cause the converted byte `ReadableStream` to hang, especially when reading the remainder of the stream or after cancellation.
- gotcha The documentation for the general `toWebReadableStream` function exists, but the primary usage examples and recent enhancements (like `makeDefaultReadableStreamFromNodeReadable` in v0.4.0) heavily emphasize the more explicit `makeByteReadableStreamFromNodeReadable` and `makeDefaultReadableStreamFromNodeReadable` functions. Relying on the `make*` functions provides clearer intent.
Install
-
npm install node-readable-to-web-readable-stream -
yarn add node-readable-to-web-readable-stream -
pnpm add node-readable-to-web-readable-stream
Imports
- makeByteReadableStreamFromNodeReadable
const makeByteReadableStreamFromNodeReadable = require('node-readable-to-web-readable-stream').makeByteReadableStreamFromNodeReadable;import { makeByteReadableStreamFromNodeReadable } from 'node-readable-to-web-readable-stream'; - makeDefaultReadableStreamFromNodeReadable
const { makeDefaultReadableStreamFromNodeReadable } = require('node-readable-to-web-readable-stream');import { makeDefaultReadableStreamFromNodeReadable } from 'node-readable-to-web-readable-stream'; - toWebReadableStream
const toWebReadableStream = require('node-readable-to-web-readable-stream').toWebReadableStream;import { toWebReadableStream } from 'node-readable-to-web-readable-stream'; - NodeJS.ReadableStream
import type { Readable } from 'node:stream';
Quickstart
import { createReadStream } from 'node:fs';
import { makeByteReadableStreamFromNodeReadable } from 'node-readable-to-web-readable-stream';
// Imagine 'large-file.bin' is a large binary file
// Create a Node.js Readable stream
const nodeReadable = createReadStream('large-file.bin');
// Convert to a web ReadableStream, specifically a byte stream for BYOB support
const webReadable = makeByteReadableStreamFromNodeReadable(nodeReadable);
// Example: Consume the webReadable using a BYOB reader
async function readStream(stream: ReadableStream<Uint8Array>) {
const reader = stream.getReader({ mode: 'byob' });
try {
while (true) {
const { value, done } = await reader.read(new Uint8Array(1024)); // Read into a pre-allocated buffer
if (done) {
console.log('Stream finished.');
break;
}
if (value) {
console.log(`Read ${value.byteLength} bytes.`);
// Process the chunk here
}
}
} catch (error) {
console.error('Error reading stream:', error);
} finally {
reader.releaseLock();
}
}
// In a real application, you'd ensure 'large-file.bin' exists or create it.
// For demonstration, we'll create a dummy file if it doesn't exist.
import { promises as fsPromises } from 'node:fs';
async function setupAndRun() {
try {
await fsPromises.access('large-file.bin');
} catch (error) {
await fsPromises.writeFile('large-file.bin', Buffer.alloc(1024 * 1024, 'A')); // 1MB dummy file
console.log('Created dummy large-file.bin');
}
readStream(webReadable);
}
setupAndRun();