[d565449] | 1 | # structuredClone polyfill
|
---|
| 2 |
|
---|
| 3 | [![Downloads](https://img.shields.io/npm/dm/@ungap/structured-clone.svg)](https://www.npmjs.com/package/@ungap/structured-clone) [![build status](https://github.com/ungap/structured-clone/actions/workflows/node.js.yml/badge.svg)](https://github.com/ungap/structured-clone/actions) [![Coverage Status](https://coveralls.io/repos/github/ungap/structured-clone/badge.svg?branch=main)](https://coveralls.io/github/ungap/structured-clone?branch=main)
|
---|
| 4 |
|
---|
| 5 | An env agnostic serializer and deserializer with recursion ability and types beyond *JSON* from the *HTML* standard itself.
|
---|
| 6 |
|
---|
| 7 | * [Supported Types](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm#supported_types)
|
---|
| 8 | * *not supported yet*: Blob, File, FileList, ImageBitmap, ImageData, and ArrayBuffer, but typed arrays are supported without major issues, but u/int8, u/int16, and u/int32 are the only safely suppored (right now).
|
---|
| 9 | * *not possible to implement*: the `{transfer: []}` option can be passed but it's completely ignored.
|
---|
| 10 | * [MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone)
|
---|
| 11 | * [Serializer](https://html.spec.whatwg.org/multipage/structured-data.html#structuredserializeinternal)
|
---|
| 12 | * [Deserializer](https://html.spec.whatwg.org/multipage/structured-data.html#structureddeserialize)
|
---|
| 13 |
|
---|
| 14 | Serialized values can be safely stringified as *JSON* too, and deserialization resurrect all values, even recursive, or more complex than what *JSON* allows.
|
---|
| 15 |
|
---|
| 16 |
|
---|
| 17 | ### Examples
|
---|
| 18 |
|
---|
| 19 | Check the [100% test coverage](./test/index.js) to know even more.
|
---|
| 20 |
|
---|
| 21 | ```js
|
---|
| 22 | // as default export
|
---|
| 23 | import structuredClone from '@ungap/structured-clone';
|
---|
| 24 | const cloned = structuredClone({any: 'serializable'});
|
---|
| 25 |
|
---|
| 26 | // as independent serializer/deserializer
|
---|
| 27 | import {serialize, deserialize} from '@ungap/structured-clone';
|
---|
| 28 |
|
---|
| 29 | // the result can be stringified as JSON without issues
|
---|
| 30 | // even if there is recursive data, bigint values,
|
---|
| 31 | // typed arrays, and so on
|
---|
| 32 | const serialized = serialize({any: 'serializable'});
|
---|
| 33 |
|
---|
| 34 | // the result will be a replica of the original object
|
---|
| 35 | const deserialized = deserialize(serialized);
|
---|
| 36 | ```
|
---|
| 37 |
|
---|
| 38 | #### Global Polyfill
|
---|
| 39 | Note: Only monkey patch the global if needed. This polyfill works just fine as an explicit import: `import structuredClone from "@ungap/structured-clone"`
|
---|
| 40 | ```js
|
---|
| 41 | // Attach the polyfill as a Global function
|
---|
| 42 | import structuredClone from "@ungap/structured-clone";
|
---|
| 43 | if (!("structuredClone" in globalThis)) {
|
---|
| 44 | globalThis.structuredClone = structuredClone;
|
---|
| 45 | }
|
---|
| 46 |
|
---|
| 47 | // Or don't monkey patch
|
---|
| 48 | import structuredClone from "@ungap/structured-clone"
|
---|
| 49 | // Just use it in the file
|
---|
| 50 | structuredClone()
|
---|
| 51 | ```
|
---|
| 52 |
|
---|
| 53 | **Note**: Do not attach this module's default export directly to the global scope, whithout a conditional guard to detect a native implementation. In environments where there is a native global implementation of `structuredClone()` already, assignment to the global object will result in an infinite loop when `globalThis.structuredClone()` is called. See the example above for a safe way to provide the polyfill globally in your project.
|
---|
| 54 |
|
---|
| 55 | ### Extra Features
|
---|
| 56 |
|
---|
| 57 | There is no middle-ground between the structured clone algorithm and JSON:
|
---|
| 58 |
|
---|
| 59 | * JSON is more relaxed about incompatible values: it just ignores these
|
---|
| 60 | * Structured clone is inflexible regarding incompatible values, yet it makes specialized instances impossible to reconstruct, plus it doesn't offer any helper, such as `toJSON()`, to make serialization possible, or better, with specific cases
|
---|
| 61 |
|
---|
| 62 | This module specialized `serialize` export offers, within the optional extra argument, a **lossy** property to avoid throwing when incompatible types are found down the road (function, symbol, ...), so that it is possible to send with less worrying about thrown errors.
|
---|
| 63 |
|
---|
| 64 | ```js
|
---|
| 65 | // as default export
|
---|
| 66 | import structuredClone from '@ungap/structured-clone';
|
---|
| 67 | const cloned = structuredClone(
|
---|
| 68 | {
|
---|
| 69 | method() {
|
---|
| 70 | // ignored, won't be cloned
|
---|
| 71 | },
|
---|
| 72 | special: Symbol('also ignored')
|
---|
| 73 | },
|
---|
| 74 | {
|
---|
| 75 | // avoid throwing
|
---|
| 76 | lossy: true,
|
---|
| 77 | // avoid throwing *and* looks for toJSON
|
---|
| 78 | json: true
|
---|
| 79 | }
|
---|
| 80 | );
|
---|
| 81 | ```
|
---|
| 82 |
|
---|
| 83 | The behavior is the same found in *JSON* when it comes to *Array*, so that unsupported values will result as `null` placeholders instead.
|
---|
| 84 |
|
---|
| 85 | #### toJSON
|
---|
| 86 |
|
---|
| 87 | If `lossy` option is not enough, `json` will actually enforce `lossy` and also check for `toJSON` method when objects are parsed.
|
---|
| 88 |
|
---|
| 89 | Alternative, the `json` exports combines all features:
|
---|
| 90 |
|
---|
| 91 | ```js
|
---|
| 92 | import {stringify, parse} from '@ungap/structured-clone/json';
|
---|
| 93 |
|
---|
| 94 | parse(stringify({any: 'serializable'}));
|
---|
| 95 | ```
|
---|