This is a serialiser designed MicroRender build to enable better serialisation of builtin and custom JS
objects than JSON.stringify()
and JSON.parse()
. One of the main focuses of the serialiser is code size,
so while other serialisers can serialise and deserialise a wider range of objects, this serialiser can do
it at a fraction of the code size.
Install from NPM:
npm install @microrender/serialiser
ESM import in javascript:
import { serialise, deserialise } from "microrender-serialiser"
serialise(object)
serialise(object, locals)
deserialise(string)
deserialise(string, locals)
serialise({hello: "world"})
<00 00 00 22 02 06 4f 62 6a 65 63 74 00 00 00 0b 03 00 68 65 6c 6c 6f 00 00 00 0b 03 00 77 6f 72 6c 64>
serialise([1, 2, 3, 4, 5])
serialise(new Map([["key", "value"], ["key2", "value2"]]))
<00 00 00 51 01 05 41 72 72 61 79 00 00 00 0e 03 01 3f f0 00 00 00 00 00 00 00 00 00 0e 03 01 40 00 00 00 00 00 00 00 00 00 00 0e 03 01 40 08 00 00 00 00 00 00 00 00 00 0e 03 01 40 10 00 00 00 00 00 00 00 00 00 0e 03 01 40 14 00 00 00 00 00 00>
<00 00 00 49 01 03 4d 61 70 00 00 00 1f 01 05 41 72 72 61 79 00 00 00 09 03 00 6b 65 79 00 00 00 0b 03 00 76 61 6c 75 65 00 00 00 21 01 05 41 72 72 61 79 00 00 00 0a 03 00 6b 65 79 32 00 00 00 0c 03 00 76 61 6c 75 65 32>
serialise(new URL("https://example.com/a/b/c"))
serialise(new Date(0))
<00 00 00 28 00 03 55 52 4c 00 00 00 1f 03 00 68 74 74 70 73 3a 2f 2f 65 78 61 6d 70 6c 65 2e 63 6f 6d 2f 61 2f 62 2f 63>
<00 00 00 28 00 04 44 61 74 65 00 00 00 1e 03 00 31 39 37 30 2d 30 31 2d 30 31 54 30 30 3a 30 30 3a 30 30 2e 30 30 30 5a>
The MicroRender serialiser uses a binary encoding format for efficiency. All numbers are stored big-endian (saves a few bytes of javascript)
- Each descriptor (an item including a description of type and length) is made up a number of components:
- Bytes 0-3: a Uint32 storing the length of the descriptor
- Byte 4: a Uint8 storing the method used to encode the descriptor:
-
0
: ToJSON- A
toJSON()
has been called on the object being serialised. - This is a composite descriptor containing a single child descriptor, a string.
- A
-
1
: Iterable- The object being serialised was an iterable (has a
@@iterator()
) method. - This is a composite descriptor containing each iterable entry as each child descriptor.
- Note that each item when iterating through JS
Map
is itself anArray
so it is stored as an iterable of iterables.
- The object being serialised was an iterable (has a
-
2
: BasicObject- The object being serialised does not have an specific ways to serialise it, so its own enumerable string-keyed properties were stored.
- This is a composite descriptor containing each key and value as child descriptors (in key-value-key-value order)
- Note that objects that store data using symbols or private (
#
) properties (eg. theRequest
object) cannot be serialised this way, and objects with mangled property names (added during minification) cannot be reliably serialised or deserialised this way either.
-
3
: Primitive- The value being serialised was a primitive (
!(value instanceof Object)
.typeof value
may beobject
ifvalue === null
) - This is a special primitive descriptor that behaves differently to the other descriptors, forming the 'leaves' of the descriptor tree.
- The value being serialised was a primitive (
-
- Bytes 5 onwards are dependent on the type of descriptor:
- Composite descriptors:
- Byte 5: a Uint8 storing the byte length of the object's constructor name
- Bytes 6-(6+value of byte 4): a UTF-8 encoded string storing the object's constructor's name
- Bytes (7+value of byte 4)-end: a series of child descriptors, stored end to end.
- Primitive descriptors
- Byte 5: a Uint8 storing the type of the descriptor, determining the encoding for the remainder of the entry:
-
0
: string- The data is a UTF-8 encoded string.
-
1
: number- The data is a Float64 number.
-
2
: bigint- The data is a BigInt64 number.
-
3
: boolean- The data is a Uint8 number, where 0 represents
false
and 1 representstrue
.
- The data is a Uint8 number, where 0 represents
-
4
: undefined- There is no data.
-
5
: object (null)- There is no data.
- Because
typeof null === "object"
, this is stored asobject
internally for consistency with the other primitive types.
-
- Byte 5: a Uint8 storing the type of the descriptor, determining the encoding for the remainder of the entry:
- Composite descriptors: