Make it possible to return more than JSON from server-only `load` functions
See original GitHub issueDescribe the problem
Right now, the output of load
in +layout.server.js
or +page.server.js
has to be serialized with JSON.stringify
so that it can be transported to the client.
Occasionally it’s useful to transport values that can’t be serialized as JSON. Date
springs to mind, along with things like this, where anything expecting selected
to be a member of options
post-deserialization will be disappointed:
export function load() {
const options = [
{ flavour: 'chocolate' },
{ flavour: 'strawberry' },
{ flavour: 'banana' }
];
const selected = options[0];
return { options, selected };
}
Describe the proposed solution
We have a proven technique for this: https://github.com/rich-harris/devalue. It’s fast, and doesn’t involve a deserialization step. (It doesn’t currently support BigInt though, we’d need to add that.)
To work with CSP, we can’t eval
the result (including by creating a <script>
), we need to import
it. Since we need to get fresh data when navigating back to a previously-visited page, we need to use a cachebusting mechanism; since modules live in a cache that we have no way of purging, we need to be careful to avoid memory leaks.
We can’t therefore do this…
export const data = {...};
…and must instead do this, so that the data can be garbage collected once it’s been used:
window.__data = {...};
On the client side, it would look something like this:
let uid = 1;
// later
await import(`${url.pathname}/__data.js`);
const data = window.__data;
delete window.__data;
Alternatives considered
There’s a variety of alternatives to devalue listed here: https://github.com/rich-harris/devalue#see-also, though I’m not aware of any reasons to favour them.
Or, we could just stick to JSON, which has better performance characteristics if you have a huge amount of data.
Importance
nice to have
Additional Information
No response
Issue Analytics
- State:
- Created a year ago
- Reactions:4
- Comments:45 (11 by maintainers)
This sounds helpful.
I’ve just bumped into the situation where serializing the
Date
type throws an error.A potential fix could be borrowed from
trpc
where end-users can set atransformer
property to support custom serialization over the network.https://github.com/trpc/trpc/blob/a321eac66d4fed9fec4ad94d2a0336353b35aebc/www/docs/server/data-transformers.md?plain=1#L43
I’d like to see something similar in SvelteKit for page endpoints.
This could be added to the
hooks.js
file.The
pageDataTransformer
hasserialize
anddeserialize
methods.When the hook is set, SvelteKit would automatically
serialize
page endpoint data being sent from the server to the client, anddeserialize
it on the client side.The advantage over providing a blessed implementation like
devalue
is that alternatives likesuperjson
allow users to extend the serializable types.My own use case involves passing
Uint8Array
binary data between the server and client. This would require a change to thedevalue
codebase, but can be added tosuperjson
trivially.If this is useful, I can create a pull request.
+1 for an approach that allows plugging a serializer like superjson. I already use it with trpc to serialize Temporal date objects and it’s a dream.