vuejs / pinia

🍍 Intuitive, type safe, light and flexible Store for Vue using the composition api with DevTools support
https://pinia.vuejs.org
MIT License
13.17k stars 1.06k forks source link

Cannot stringify POJOs with symbolic keys #193

Closed nles closed 3 years ago

nles commented 4 years ago

When using Pinia from a fetch function in page with Nuxt, we get the following error for each Pinia store initiated.

WARN: Cannot stringify POJOs with symbolic keys Symbol(vfa.key.reactiveIdentifier)

It doesn't seem to affect the functionality, but this seems to be something that shouldn't happen...

Bug can be reproduced with a clean Nuxt installation:

npx create-nuxt-app piniabug
cd piniabug
yarn add pinia @vue/composition-api
# create a store according to example in Pinia README to stores/main.js
# setup the Nuxt plugin according to Pinia README
# setup composition-api as Nuxt plugin (see below)
# create a fetch function in the pages/index.vue file (see below)

plugins/composition-api.js

import Vue from 'vue';
import VueCompositionApi from '@vue/composition-api';

Vue.use(VueCompositionApi);

export * from '@vue/composition-api';

pages/index.vue (relevant parts)

import { useMainStore } from '@/stores/main'
...
 fetch({ req }) {
    const main = useMainStore(req);
    console.log(main.state);
  },
...

The error goes away if I use for example lodash cloneDeep on the req before passing it in to useMainStore, but that seems to break Pinia somehow, so that store modifications done during the fetch method are not available in the client-side.

posva commented 4 years ago

Can you provide a stacktrace? Where is that warning coming from?

nles commented 4 years ago

I couldn't get Nuxt to print out a trace, but I figured by grepping, that it's coming from node_modules/@nuxt/devalue/devalue.js line 76. I googled to find few similar issues, and it seems to boil down to Nuxt logging warnings when objects with symbols are being set to nuxtState (to be rendered in the server for the client to pick it up). Composition api sets vfa.key.reactiveIdentifier symbol to the reactive Pinia store that is set to nuxtState, which was causing the logger to show warnings.

A decent fix without any additional dependencies seems to be to "clone" the object with JSON.stringify and JSON.parse before setting it to nuxtState.

Opened up a pull request with this fix at https://github.com/posva/pinia/pull/194

posva commented 4 years ago

Thanks for the PR but is that warn an error or just a warn? Cloning the object with JSON.stringify and parse has a cost that would be better to avoid.

Have you tried https://github.com/nuxt-community/composition-api for Nuxt ?

nles commented 4 years ago

It's warn only, and initially doesn't seem to be breaking anything. However, when I applied this fix to an app I'm working on, I noticed at least one case of client-side state being "polluted", likely by Nuxt state being restored with the reactive object (I couldn't replicate it easily, so there could have been something else at play here as well...)

I tried nuxt-composition-api, but I didn't manage to get Pinia working with it (failed with must call Vue.use(plugin) before using any function). I don't really think it matters anyway, since the issue is not related to how composition-api is initiated, but with the fact that there are symbols in the object going in to nuxtState.

I get that the JSON.stringify & parse operation is not that optimal... Another way might be to just get rid of the vfa.key.reactiveIdentifier symbol before setting stuff to nuxtState?

I created a simple repro on CodeSandbox: https://codesandbox.io/s/exciting-johnson-sq250. The warning comes up in the terminal view when the browser view is refreshed (since it happens on server-side only, and CodeSandbox omits the warning on the first render for some reason).

posva commented 3 years ago

After updating the dependencies this doesn't seem to be a problem anymore: https://codesandbox.io/s/friendly-dawn-9b3fi?file=/pages/index.vue

MartinMalinda commented 3 years ago

This is still an issue on pinia 0.5.2 and Nuxt 2.13:

https://codesandbox.io/s/exciting-johnson-sq250

In my app, I'm also getting Maximum call stack exceeded which causes a crash on the server. This is caused also by node_modules/@nuxt/devalue/devalue.js line 76. Would JSON.stringify really be a performance hit compared to what Nuxt is doing right now? But it makes sense if this needs to be fixed on Nuxt side primarily.

posva commented 3 years ago

This seems fixed: https://github.com/posva/pinia-example-nuxt. If you can reproduce in a boiled down reproduction with updated deps, open a new issue

Would JSON.stringify really be a performance hit compared to what Nuxt is doing right now? But it makes sense if this needs to be fixed on Nuxt side primarily.

It depends. If your state is serializable, you could also convert it to json instead. Take a look at the nuxt folder, it's very easy to create a custom build module

MartinMalinda commented 3 years ago

@posva thanks for this example. I figured out I got this error from somewhere else, perhaps by doing console.error on the server which caused nuxt-sentry trying to pass the error to the client and the error failed to serialize.

I'm still getting the cannot stringify pojos with symobolic keys warning but it's not breaking for me anymore. I might be passing something wrong to pinia state. I'll create a new issue once I identify what state specifically causes it.