jotaijs / jotai-devtools

A powerful toolkit to enhance your development experience with Jotai
https://jotai.org/docs/tools/devtools
MIT License
124 stars 29 forks source link

Atom rendering hangs on complex objects (such as the Firebase User object) #120

Closed staticshock closed 6 months ago

staticshock commented 7 months ago

The dev tools are choking for me on the Firebase Auth user object, causing the page to go unresponsive.

Looks like javascript-stringify recursively descends into the Firebase User object and finds references to functions, for which it stringifies and inlines the code, no matter how bulky. This eventually become a beast to render and hangs my browser.

// with whitespace
javascriptStringify(firebaseUser, null, 2).length
288227

// without whitespace
javascriptStringify(firebaseUser).length
158985

// without functions
javascriptStringify(
  firebaseUser,
  ((value, indent, stringify) => typeof value === 'function' ? 'function' : stringify(value)),
  2
).length
105180

// without whitespace and functions
javascriptStringify(
  firebaseUser,
  ((value, indent, stringify) => typeof value === 'function' ? 'function' : stringify(value))
).length
43842

// without javascriptStringify
JSON.stringify(firebaseUser).length
1324

A few suggestions:

  1. Use JSON.stringify() if atomValue.toJSON() is present. The Firebase User object implements this, which is why the result in my final example is so tiny.
  2. Stringify functions without bodies, maybe via: `${function.name}() { … }`
  3. Userland escape hatch: Maybe look for atom.valueToString() and use that instead if available?
arjunvegda commented 7 months ago

Thanks for reaching out!

The idea behind using javascript-stringify was to produce output that is identical to JavaScript code. I'm not sure if those suggestions would keep the behavior same for the existing users.

Could you try marking the atom as yourAtom.debugPrivate=true? This would hide the atom from the DevTools (if you're using default props) and should make the UI somewhat usable.

As far as the solution goes, I wonder if allowing users to provide their own serializer would make sense 🤔

Also, is it possible for you to provide the big firebase object that I can play around with? Perhaps we could explore "if size is greater than X then stringify functions without bodies" kinda path.

staticshock commented 7 months ago

To get a firebase auth object, I think you can do something like this:

git clone https://github.com/milliorn/nextjs-13-firebase-starter
cd nextjs-13-firebase-starter
npm install

And then follow the "set up firebase" instructions in that repo's README. Add a new email/password into firebase auth via their admin console, then try to log in as that user from the app.

arjunvegda commented 6 months ago

I gave this a little bit of thought, I think we should detect the size of the object and skip displaying the information altogether.

Exposing a consumer-facing serializer would mean that we can no longer make certain assumptions about how the data is going to be displayed on the UI which could lead to bugs.

Could you help determine the size of the object at which Jotai DevTools starts choking? Ideally, it'd be nice to collect this data with the CPU throttled down by 4x.

staticshock commented 6 months ago

Sorry, I've stopped experimenting with Jotai for the moment and moved on to other projects.