kit icon indicating copy to clipboard operation
kit copied to clipboard

Allow the serialisation/deserialisation of non-POJOs

Open carlosV2 opened this issue 1 year ago • 7 comments

Describe the problem

In my current project I'm in need of sending data back and forth the server for which I've built a series of objects that I can easily serialise and deserialise with the amazing devalue library. This includes the initial load of data via some contraption like this:

export const load = (async () => {
  const data = // ... load data. f.e. from DB
  return { data: pack(data) };
}) satisfies PageServerLoad;

In this example, the function pack is a wrapper of the stringify function from devalue with a set of object types passed to this function as reducers.

On the client side, I'm obviously running the opposite method to get the data back with the equivalent revivers.

I particularly like this option because it allows me to introduce simple functions to these objects that I can run seamlessly regardless of the environment.

At the current stage, however, I'm in need of deduplicating code by separating layout logic from page logic. More often than not, I need to use the layout data to perform some logic on the page (think about the layout loading a resource and the page validating access to this resource).

Due to the current SvelteKit behaviour I can't return any non-POJO on the layout as it will be serialised for the client so I'm forced to use my pack function. However, when I pull this date in the page, I have to first unpack it to be able to use it which feels like a waste of resources.

The same waste of resources can happen on the client side. Attempting to use the data in the client layout requires to unpack it first but so does attempting to use it in the page. With a solution proposed here, the serialisation could be handled by SvelteKit and the same result could be used as many times as needed.

Describe the proposed solution

I think it would be nice if we could add some code in the hooks.server.ts and the hooks.client.ts to allocate for this. For example:

type Reducer = (value: any) => any;
type Reviver = (value: any) => any;
type SerialiseHandle = { reducer?: Reducer, reviver?: Reviver };

export const serialisationHandles: Record<string, SerialiseHandle> = {
   MyObj: {
      reducer: (value) => value instanceof MyObj && [value.param1, value.param2],
      reviver: ([param1, param2]) => new MyObject(param1, param2)
   },
   MyOtherObject: { /* ... */ }
}

This could be replicated similarly on the client hook thus allowing for the potential serialisation/deserialisation of dedicated object (i.e. a server version of MyObj and a client version of it). Alternatively, the handles can be abstracted into a third file to keep consistency between both environments.

Alternatives considered

I tried by returning the raw object on the layout which allows for the exact object to be retrieved on the page. Then I tried to re-return the object with the custom serialisation applied but it still complained about the non-POJOs.

Right now my only options are to either pack/unpack the data or to reload it altogether which it is, in both cases, a waste of compute power.

In the client side, there is the possibility of using a context to prevent from wasting too many resources.

Importance

nice to have

Additional Information

No response

carlosV2 avatar Mar 11 '23 01:03 carlosV2