question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Make it possible to return more than JSON from server-only `load` functions

See original GitHub issue

Describe 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:closed
  • Created a year ago
  • Reactions:4
  • Comments:45 (11 by maintainers)

github_iconTop GitHub Comments

30reactions
ifiokjrcommented, Aug 24, 2022

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 a transformer 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.

// hooks.js
import superjson from 'superjson';

// This hook adds custom serialization of json within page endpoints.
export const pageDataTransformer = superjson;

The pageDataTransformer has serialize and deserialize methods.

When the hook is set, SvelteKit would automatically serialize page endpoint data being sent from the server to the client, and deserialize it on the client side.

The advantage over providing a blessed implementation like devalue is that alternatives like superjson 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 the devalue codebase, but can be added to superjson trivially.

If this is useful, I can create a pull request.

16reactions
alexturpincommented, Aug 25, 2022

+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.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Nodejs & Express: How to send multiple Json variable from ...
Use this in server side code. I think this will help you. This is the example of multiple value sent from server to...
Read more >
Loading data • Docs • SvelteKit
A server load function must return data that can be serialized with devalue — anything that can be represented as JSON plus things...
Read more >
Breaking changes in SvelteKit, August 2022 - Josh Collinsworth
We just need to import it, then wrap whatever data we return in that function call. // The new way: import { json...
Read more >
Fetch - The Modern JavaScript Tutorial
There are multiple ways to send a network request and get information from the server. The fetch() method is modern and versatile, so...
Read more >
How to return a json object from a Python function?
The full-form of JSON is JavaScript Object Notation. It means that a script (executable) file which is made of text in a programming ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found