flightcontrolhq / superjson

Safely serialize JavaScript expressions to a superset of JSON, which includes Dates, BigInts, and more.
https://www.flightcontrol.dev?ref=superjson
MIT License
4.13k stars 91 forks source link

`stringify()` throws `Converting circular structure to JSON ` when stringifying `onClick` event #232

Closed skoshx closed 1 year ago

skoshx commented 1 year ago

First off, thanks a lot for this package, it comes handy in many cases!

I have a requirement of being able to stringify complex objects like for instance the onClick React event, and superjson should be able to handle Circular references, as the tests and previous PR's show, however stringify() still throws when stringifying the onClick event in React.

I'm using superjson version 1.12.2

Minimal repro for example in NextJS page:

import { type NextPage } from "next";
import Head from "next/head";
import Link from "next/link";
import SuperJSON from "superjson";

const Home: NextPage = () => {
  function throwSomeError(e: any) {
    SuperJSON.stringify(e) // 👈 throws
  }

  return (
    <>
      <Head>
        <title>...</title>
        <meta name="description" content="..." />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <main>
          <button onClick={throwSomeError}>Throw</button>
      </main>
    </>
  );
};

export default Home;

This is the complete error:

caught (in promise) TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'HTMLButtonElement'
    |     property '__reactFiber$194th5rez4d' -> object with constructor 'FiberNode'
    --- property 'stateNode' closes the circle
    at JSON.stringify (<anonymous>)
Skn0tt commented 1 year ago

Hi @skoshx! SuperJSON can recreate the shape of an object, but it won't be able to hook it up to the correct DOM elements after deserializing, that's just a limitation of string serialization. Could you elaborate on your usecase for serializing the evt value?

skoshx commented 1 year ago

Thanks for the quick reply! I understand that it won't be possible to serialize it back to correct DOM elements, and that's completely fine in my case. I was just wondering, would it be possible to make stringify() work even in these cases, where there will be "loss" of identity

My use case is that I want to be able to capture all kinds of events that happen, so I can imitate a call (for instance onClick) as closely as possible. As such, losing references to the DOM and stuff like that is completely fine, because we will be able to restore those when the merging them with the events themselves.

It's completely fine if this is something that is out of the scope of SuperJSON, then I will just handle these edge cases on my own! :D

Skn0tt commented 1 year ago

Okay, got it! I think this out-of-scope for SuperJSON, yes.