Skip to content

Commit 5d3d0d4

Browse files
authored
breaking: remove polyfills & top level await (#41)
* breaking: make fetch-blob an optional dependency also lazy load fetch-blob when necessary * breaking: now depend on built-in DOMException * remove all polyfills * breaking summary
1 parent 7826ab1 commit 5d3d0d4

File tree

9 files changed

+103
-42
lines changed

9 files changed

+103
-42
lines changed

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,35 @@ It's not trying to interfere with the changing spec by using other properties th
3333
( The current minium supported browser I have chosen to support is the ones that can handle import/export )<br>
3434
( Some parts are lazy loaded when needed )
3535

36+
### Updating from 2.x to 3.x
37+
v3 removed all top level await that conditionally loaded polyfills like
38+
WritableStream, DOMException, and Blob/File. considering that now all latest
39+
up to date env have this built in globally on `globalThis` namespace. This makes
40+
the file system adapter lighter for ppl who want a smaller bundle and supports
41+
newer engines.
42+
43+
But if you still need to provide polyfills for older environments
44+
then you can provide your own polyfill and set it up with our config before any
45+
other script is evaluated
46+
47+
```js
48+
49+
import config from 'native-file-system-adapter/config.js'
50+
// This is the default config that you could override as needed.
51+
Object.assign(config, {
52+
ReadableStream: globalThis.ReadableStream,
53+
WritableStream: globalThis.WritableStream,
54+
TransformStream: globalThis.TransformStream,
55+
DOMException: globalThis.DOMException,
56+
Blob: globalThis.Blob,
57+
File: globalThis.File
58+
})
59+
// continue like normal.
60+
import xyz from 'native-file-system-adapter'
61+
```
62+
63+
64+
3665
### ES import in browser
3766

3867
```html

package-lock.json

Lines changed: 15 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "native-file-system-adapter",
3-
"version": "2.0.3",
3+
"version": "3.0.0",
44
"description": "Native File System API",
55
"main": "src/es6.js",
66
"module": "./src/es6.js",
@@ -49,11 +49,7 @@
4949
],
5050
"homepage": "https://github.com/jimmywarting/native-file-system-adapter#readme",
5151
"optionalDependencies": {
52-
"web-streams-polyfill": "^3.1.1"
53-
},
54-
"dependencies": {
55-
"fetch-blob": "^3.1.5",
56-
"node-domexception": "^1.0.0"
52+
"fetch-blob": "^3.2.0"
5753
},
5854
"standard": {
5955
"globals": [

src/FileSystemWritableFileStream.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
/** @type {typeof WritableStream} */
2-
const ws = globalThis.WritableStream || await import('https://cdn.jsdelivr.net/npm/web-streams-polyfill@3/dist/ponyfill.es2018.mjs').then(r => r.WritableStream).catch(() => import('web-streams-polyfill').then(r => r.WritableStream))
1+
import config from './config.js'
32

4-
// TODO: add types for ws
5-
class FileSystemWritableFileStream extends ws {
3+
const { WritableStream } = config
4+
5+
class FileSystemWritableFileStream extends WritableStream {
66
constructor (...args) {
77
super(...args)
88

src/adapters/downloader.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
/* global Blob, DOMException, Response, MessageChannel */
22

33
import { errors } from '../util.js'
4+
import config from '../config.js'
5+
6+
const {
7+
WritableStream,
8+
TransformStream,
9+
DOMException,
10+
Blob
11+
} = config
412

513
const { GONE } = errors
614
// @ts-ignore
715
const isSafari = /constructor/i.test(window.HTMLElement) || window.safari || window.WebKitPoint
8-
let TransformStream = globalThis.TransformStream
9-
let WritableStream = globalThis.WritableStream
1016

1117
export class FileHandle {
1218
constructor (name = 'unkown') {
@@ -26,12 +32,6 @@ export class FileHandle {
2632
* @param {object} [options={}]
2733
*/
2834
async createWritable (options = {}) {
29-
if (!TransformStream) {
30-
// @ts-ignore
31-
const ponyfill = await import('https://cdn.jsdelivr.net/npm/web-streams-polyfill@3/dist/ponyfill.es2018.mjs')
32-
TransformStream = ponyfill.TransformStream
33-
WritableStream = ponyfill.WritableStream
34-
}
3535
const sw = await navigator.serviceWorker?.getRegistration()
3636
const link = document.createElement('a')
3737
const ts = new TransformStream()

src/adapters/memory.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import { errors } from '../util.js'
2-
/** @type {typeof window.File} */
3-
const File = globalThis.File || await import('fetch-blob/file.js').then(m => m.File)
4-
/** @type {typeof window.Blob} */
5-
const Blob = globalThis.Blob || await import('fetch-blob').then(m => m.Blob)
2+
import config from '../config.js'
63

4+
const { File, Blob, DOMException } = config
75
const { INVALID, GONE, MISMATCH, MOD_ERR, SYNTAX, SECURITY, DISALLOWED } = errors
86

97
export class Sink {

src/adapters/node.js

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,34 @@
11
import fs from 'node:fs/promises'
22
import { join } from 'node:path'
3-
import 'node-domexception'
4-
import Blob from 'fetch-blob'
5-
import { fileFrom } from 'fetch-blob/from.js'
63
import { errors } from '../util.js'
7-
// import mime from 'mime-types'
4+
5+
import config from '../config.js'
6+
7+
const {
8+
DOMException
9+
} = config
810

911
const { INVALID, GONE, MISMATCH, MOD_ERR, SYNTAX } = errors
1012

11-
export class Sink {
13+
/**
14+
* @see https://github.com/node-fetch/fetch-blob/blob/0455796ede330ecffd9eb6b9fdf206cc15f90f3e/index.js#L232
15+
* @param {*} object
16+
* @returns {object is Blob}
17+
*/
18+
function isBlob (object) {
19+
return (
20+
object &&
21+
typeof object === 'object' &&
22+
typeof object.constructor === 'function' &&
23+
(
24+
typeof object.stream === 'function' ||
25+
typeof object.arrayBuffer === 'function'
26+
) &&
27+
/^(Blob|File)$/.test(object[Symbol.toStringTag])
28+
)
29+
}
1230

31+
export class Sink {
1332
/**
1433
* @param {fs.FileHandle} fileHandle
1534
* @param {number} size
@@ -65,7 +84,7 @@ export class Sink {
6584
chunk = new Uint8Array(chunk)
6685
} else if (typeof chunk === 'string') {
6786
chunk = Buffer.from(chunk)
68-
} else if (chunk instanceof Blob) {
87+
} else if (isBlob(chunk)) {
6988
for await (const data of chunk.stream()) {
7089
const res = await this._fileHandle.writev([data], this._position)
7190
this._position += res.bytesWritten
@@ -101,6 +120,9 @@ export class FileHandle {
101120
await fs.stat(this._path).catch(err => {
102121
if (err.code === 'ENOENT') throw new DOMException(...GONE)
103122
})
123+
124+
// TODO: replace once https://github.com/nodejs/node/issues/37340 is fixed
125+
const { fileFrom } = await import('fetch-blob/from.js')
104126
return fileFrom(this._path)
105127
}
106128

src/config.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const config = {
2+
ReadableStream: globalThis.ReadableStream,
3+
WritableStream: globalThis.WritableStream,
4+
TransformStream: globalThis.TransformStream,
5+
DOMException: globalThis.DOMException,
6+
Blob: globalThis.Blob,
7+
File: globalThis.File,
8+
}
9+
10+
export default config

test/test-node.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { existsSync, mkdirSync, rmdirSync } from 'node:fs'
2-
import { getOriginPrivateDirectory } from '../src/es6.js'
2+
import config from '../src/config.js'
33
import steps from './test.js'
4+
import File from 'fetch-blob/file.js'
5+
import { getOriginPrivateDirectory } from '../src/es6.js'
46
import { cleanupSandboxedFileSystem } from '../test/util.js'
57

68
let hasFailures = false
@@ -12,6 +14,7 @@ async function test (fs, step, root) {
1214
console.log(`[OK]: ${fs} ${step.desc}`)
1315
} catch (err) {
1416
console.log(`[ERR]: ${fs} ${step.desc}\n\t-> ${err.message}`)
17+
console.error(err.stack)
1518
hasFailures = true
1619
}
1720
}
@@ -21,6 +24,7 @@ async function start () {
2124
if (!existsSync(testFolderPath)) {
2225
mkdirSync(testFolderPath)
2326
}
27+
config.File = File
2428
const root = await getOriginPrivateDirectory(import('../src/adapters/node.js'), './testfolder')
2529
const memory = await getOriginPrivateDirectory(import('../src/adapters/memory.js'))
2630

0 commit comments

Comments
 (0)