Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Date type mismatch between Client and Server causing Runtime "TypeError" #768

Closed
FlorianPallas opened this issue Feb 23, 2023 · 10 comments
Closed

Comments

@FlorianPallas
Copy link

Describe the bug

When using createServerData$(...) for example, any date objects transferred from the server to the client will be serialized into strings and remain that way on the client, causing a type mismatch between the client and server version of the affected component.

This can cause visual differences or even errors when the client needs to rerender the component (Navigation, Hot Reload, ...) because the client expects a Date object to be present.

Steps to Reproduce the Bug or Issue

Using the minimal example with SSR (and TypeScript), make the following changes to the index page:

...
  export default function Home() {
+   const date = createServerData$(() => new Date());
  
    return (
      <main>
+       <p>{date()?.toLocaleDateString()}</p>
...

The initial render is as expected. But when switching to the about page and switching back, an error occurs. The client fails to call toLocaleDateString(), as the function only exists on Date objects, not strings.

Expected behavior

The client should turn the date string back into a Date object, preventing type issues like this.

Screenshots or Videos

Screenshot from 2023-02-23 21-18-05

Platform

  • OS: Linux
  • Browser: Chrome
  • Version: v0.2.21
@boehs
Copy link
Contributor

boehs commented Feb 26, 2023

Fascinating problem, the complexity for a fix seems astronomical. Obviously, the workaround is to just to that serialization client side

@arbassett
Copy link
Contributor

arbassett commented Feb 27, 2023

So the behaver that the server is doing is kind of funky as really you should get a error on the server as well but it appears on the server the data is not getting serialized but passed directly.

The typing issue for this is the same issue trpc/trpc#3261 ran into where the return types would not get changed properly for typescript and blindly say it can send none json serializable types over the wire (Date, Set, Map). what you should do is instead user something like superjson to send these values over the wire.

@lxsmnsyc
Copy link
Member

lxsmnsyc commented Mar 7, 2023

tbf SolidJS's serialization supports JS values like Date, but this seems to be more of an issue with the serializer itself.

@arbassett
Copy link
Contributor

arbassett commented Mar 7, 2023

tbf SolidJS's serialization supports JS values like Date, but this seems to be more of an issue with the serializer itself.

Solid's serialization is working perfectly. What's happening is server$ behavior's is different on client and server...

When the server does a SSR server$ is directly invoked

/**
*  currently in the context of the server render you can basically think this as const fn = () => new Data()
*/
const $$server_module0$1 = server$.createHandler(async function $$serverHandler0() {
  return new Date();
}, "/_m/0dbe216f23/routeData", true);
server$.registerHandler("/_m/0dbe216f23/routeData", $$server_module0$1);

and on the client server$ is a fetch to the generate endpoint

/** 
* again you can think of this as const fn = () => fetch('/_m/0dbe216f23/routeData')
*/
const $$server_module0$1 = server$.createFetcher('/_m/0dbe216f23/routeData', false)

So when the server does a SSR render you get a raw Date object back from the server function while on the client its over a network boundary so it gets serialized by the server function middleware. What needs to happen is the server render also needs to serialize the repose to match the client

Building on my previous comment server$ typing's don't reflect what is really happening which is exactly what trpc went though.. what should happen is the return type for server$ should transform it into what's really happening ex.

  • date -> string
  • map -> {}

That leaves the question what do you do if you do want to pass a raw date or map over the wire.. well you need to use something like superjson. but you would loose your typings

@lxsmnsyc
Copy link
Member

lxsmnsyc commented Mar 8, 2023

ah right, server$ did use a different form of serializer than what Solid is currently using.

@arbassett
Copy link
Contributor

i stared work in #792 but ryan noted that its now being extracted to Bling so will be moving work to there.

tracking issue: TanStack/bling#9

@lxsmnsyc
Copy link
Member

lxsmnsyc commented Mar 8, 2023

@arbassett you can probably expand on the fact that Bling currently only supports JSON values

@antl3x
Copy link

antl3x commented Sep 18, 2023

What about support eJson like meteor ddp?

https://github.com/primus/ejson

@lxsmnsyc
Copy link
Member

@antmoux we have a new serializer being used in SolidJS. It's most likely sooner or later we'll get to address this issue

@ryansolid
Copy link
Member

In setting up for SolidStarts next Beta Phase built on Nitro and Vinxi we are closing all PRs/Issues that will not be merged due to the system changing. If you feel your issue was closed by mistake. Feel free to re-open it after updating/testing against 0.4.x release. Thank you for your patience.

See #1139 for more details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants