Skip to content

Commit a1a182e

Browse files
authored
breaking: Remove dependency on streams polyfill (#149)
* Remove dependency on streams polyfill * require node v16.7 * change test version * only test ubuntu * remove changelog
1 parent 57e4dae commit a1a182e

12 files changed

+65
-231
lines changed

.github/PULL_REQUEST_TEMPLATE.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@
1212

1313
-------------------------------------------------------------------------------------------------
1414

15-
<!-- Mark what you have done, Remove unnecessary ones. Add new tasks that may fit (like TODO's) -->
15+
<!-- Mark what you have done with [x], Remove unnecessary ones. Add new tasks that may fit (like TODO's) -->
1616
- [ ] I prefixed the PR-title with `docs: `, `fix(area): `, `feat(area): ` or `breaking(area): `
17-
- [ ] I updated ./CHANGELOG.md with a link to this PR or Issue
1817
- [ ] I updated the README.md
1918
- [ ] I Added unit test(s)
2019

.github/workflows/ci.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,16 @@ jobs:
1313
test:
1414
strategy:
1515
matrix:
16-
os: [ubuntu-latest, windows-latest, macOS-latest]
17-
node: ["17.3"]
16+
os: [ubuntu-latest]
17+
node: ["16", "18", "20"]
1818

1919
runs-on: ${{ matrix.os }}
2020

2121
steps:
2222
- uses: actions/checkout@v2
2323
- uses: actions/setup-node@v2
2424
with:
25-
node-version: '17.3'
25+
node-version: ${{ matrix.node }}
2626
- run: npm install
2727
- run: npm test
2828
- run: npm run report -- --colors

CHANGELOG.md

-98
This file was deleted.

README.md

+5-10
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ npm install fetch-blob
2626
- CommonJS was replaced with ESM
2727
- The node stream returned by calling `blob.stream()` was replaced with whatwg streams
2828
- (Read "Differences from other blobs" for more info.)
29-
3029
</details>
3130

3231
<details>
@@ -48,14 +47,10 @@ npm install fetch-blob
4847

4948
```js
5049
// Ways to import
51-
// (PS it's dependency free ESM package so regular http-import from CDN works too)
52-
import Blob from 'fetch-blob'
53-
import File from 'fetch-blob/file.js'
54-
55-
import {Blob} from 'fetch-blob'
56-
import {File} from 'fetch-blob/file.js'
50+
import { Blob } from 'fetch-blob'
51+
import { File } from 'fetch-blob/file.js'
5752

58-
const {Blob} = await import('fetch-blob')
53+
const { Blob } = await import('fetch-blob')
5954

6055

6156
// Ways to read the blob:
@@ -75,7 +70,6 @@ It will not read the content into memory. It will only stat the file for last mo
7570

7671
```js
7772
// The default export is sync and use fs.stat to retrieve size & last modified as a blob
78-
import blobFromSync from 'fetch-blob/from.js'
7973
import {File, Blob, blobFrom, blobFromSync, fileFrom, fileFromSync} from 'fetch-blob/from.js'
8074

8175
const fsFile = fileFromSync('./2-GiB-file.bin', 'application/octet-stream')
@@ -119,7 +113,8 @@ blob = undefined // loosing references will delete the file from disk
119113

120114
### Creating Blobs backed up by other async sources
121115
Our Blob & File class are more generic then any other polyfills in the way that it can accept any blob look-a-like item
122-
An example of this is that our blob implementation can be constructed with parts coming from [BlobDataItem](https://github.com/node-fetch/fetch-blob/blob/8ef89adad40d255a3bbd55cf38b88597c1cd5480/from.js#L32) (aka a filepath) or from [buffer.Blob](https://nodejs.org/api/buffer.html#buffer_new_buffer_blob_sources_options), It dose not have to implement all the methods - just enough that it can be read/understood by our Blob implementation. The minium requirements is that it has `Symbol.toStringTag`, `size`, `slice()` and either a `stream()` or a `arrayBuffer()` method. If you then wrap it in our Blob or File `new Blob([blobDataItem])` then you get all of the other methods that should be implemented in a blob or file
116+
An example of this is that our blob implementation can be constructed with parts coming from [BlobDataItem](https://github.com/node-fetch/fetch-blob/blob/8ef89adad40d255a3bbd55cf38b88597c1cd5480/from.js#L32) (aka a filepath) or from [buffer.Blob](https://nodejs.org/api/buffer.html#buffer_new_buffer_blob_sources_options), It dose not have to implement all the methods - just enough that it can be read/understood by our Blob implementation. The minium requirements is that it has `Symbol.toStringTag`, `size`, `slice()`, `stream()` methods (the stream method
117+
can be as simple as being a sync or async iterator that yields Uint8Arrays. If you then wrap it in our Blob or File `new Blob([blobDataItem])` then you get all of the other methods that should be implemented in a blob or file (aka: text(), arrayBuffer() and type and a ReadableStream)
123118

124119
An example of this could be to create a file or blob like item coming from a remote HTTP request. Or from a DataBase
125120

file.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Blob from './index.js'
1+
import { Blob } from './index.js'
22

33
const _File = class File extends Blob {
44
#lastModified = 0
@@ -46,4 +46,3 @@ const _File = class File extends Blob {
4646

4747
/** @type {typeof globalThis.File} */// @ts-ignore
4848
export const File = _File
49-
export default File

from.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import { tmpdir } from 'node:os'
1010
import process from 'node:process'
1111
import DOMException from 'node-domexception'
1212

13-
import File from './file.js'
14-
import Blob from './index.js'
13+
import { File } from './file.js'
14+
import { Blob } from './index.js'
1515

1616
const { stat, mkdtemp } = fs
1717
let i = 0, tempDir, registry

index.js

+25-25
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,32 @@
11
/*! fetch-blob. MIT License. Jimmy Wärting <https://jimmy.warting.se/opensource> */
22

3-
// TODO (jimmywarting): in the feature use conditional loading with top level await (requires 14.x)
4-
// Node has recently added whatwg stream into core
5-
6-
import './streams.cjs'
3+
if (!globalThis.ReadableStream) {
4+
try {
5+
const process = await import('node:process').then(m => m.default)
6+
const { emitWarning } = process
7+
try {
8+
process.emitWarning = () => {}
9+
const streams = await import('node:stream/web').then(m => m.default)
10+
Object.assign(globalThis, streams)
11+
process.emitWarning = emitWarning
12+
} catch (error) {
13+
process.emitWarning = emitWarning
14+
throw error
15+
}
16+
} catch (error) {}
17+
}
718

819
// 64 KiB (same size chrome slice theirs blob into Uint8array's)
920
const POOL_SIZE = 65536
1021

11-
/** @param {(Blob | Uint8Array)[]} parts */
12-
async function * toIterator (parts, clone = true) {
22+
/**
23+
* @param {(Blob | Uint8Array)[]} parts
24+
* @param {boolean} clone
25+
* @returns {AsyncIterableIterator<Uint8Array>}
26+
*/
27+
async function * toIterator (parts, clone) {
1328
for (const part of parts) {
14-
if ('stream' in part) {
15-
yield * (/** @type {AsyncIterableIterator<Uint8Array>} */ (part.stream()))
16-
} else if (ArrayBuffer.isView(part)) {
29+
if (ArrayBuffer.isView(part)) {
1730
if (clone) {
1831
let position = part.byteOffset
1932
const end = part.byteOffset + part.byteLength
@@ -26,16 +39,9 @@ async function * toIterator (parts, clone = true) {
2639
} else {
2740
yield part
2841
}
29-
/* c8 ignore next 10 */
3042
} else {
31-
// For blobs that have arrayBuffer but no stream method (nodes buffer.Blob)
32-
let position = 0, b = (/** @type {Blob} */ (part))
33-
while (position !== b.size) {
34-
const chunk = b.slice(position, Math.min(b.size, position + POOL_SIZE))
35-
const buffer = await chunk.arrayBuffer()
36-
position += buffer.byteLength
37-
yield new Uint8Array(buffer)
38-
}
43+
// @ts-ignore TS Think blob.stream() returns a node:stream
44+
yield * part.stream()
3945
}
4046
}
4147
}
@@ -139,11 +145,6 @@ const _Blob = class Blob {
139145
* @return {Promise<ArrayBuffer>}
140146
*/
141147
async arrayBuffer () {
142-
// Easier way... Just a unnecessary overhead
143-
// const view = new Uint8Array(this.size);
144-
// await this.stream().getReader({mode: 'byob'}).read(view);
145-
// return view.buffer;
146-
147148
const data = new Uint8Array(this.size)
148149
let offset = 0
149150
for await (const chunk of toIterator(this.#parts, false)) {
@@ -218,7 +219,7 @@ const _Blob = class Blob {
218219
}
219220
}
220221

221-
const blob = new Blob([], { type: String(type).toLowerCase() })
222+
const blob = new Blob([], { type: `${type}` })
222223
blob.#size = span
223224
blob.#parts = blobParts
224225

@@ -251,4 +252,3 @@ Object.defineProperties(_Blob.prototype, {
251252

252253
/** @type {typeof globalThis.Blob} */
253254
export const Blob = _Blob
254-
export default Blob

package.json

+7-9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "fetch-blob",
3-
"version": "3.1.5",
3+
"version": "4.0.0",
44
"description": "Blob & File implementation in Node.js, originally from node-fetch.",
55
"main": "index.js",
66
"type": "module",
@@ -10,8 +10,7 @@
1010
"file.d.ts",
1111
"index.js",
1212
"index.d.ts",
13-
"from.d.ts",
14-
"streams.cjs"
13+
"from.d.ts"
1514
],
1615
"scripts": {
1716
"test": "node --experimental-loader ./test/http-loader.js ./test/test-wpt-in-node.js",
@@ -26,7 +25,7 @@
2625
"node-fetch"
2726
],
2827
"engines": {
29-
"node": "^12.20 || >= 14.13"
28+
"node": ">=16.7"
3029
},
3130
"author": "Jimmy Wärting <[email protected]> (https://jimmy.warting.se)",
3231
"license": "MIT",
@@ -35,9 +34,9 @@
3534
},
3635
"homepage": "https://github.com/node-fetch/fetch-blob#readme",
3736
"devDependencies": {
38-
"@types/node": "^18.0.2",
39-
"c8": "^7.11.0",
40-
"typescript": "^4.5.4"
37+
"@types/node": "^16.5.0",
38+
"c8": "^7.13.0",
39+
"typescript": "^5.0.4"
4140
},
4241
"funding": [
4342
{
@@ -50,7 +49,6 @@
5049
}
5150
],
5251
"dependencies": {
53-
"node-domexception": "^1.0.0",
54-
"web-streams-polyfill": "^3.0.3"
52+
"node-domexception": "^1.0.0"
5553
}
5654
}

streams.cjs

-51
This file was deleted.

0 commit comments

Comments
 (0)