vercel / next.js

The React Framework
https://nextjs.org
MIT License
124.82k stars 26.64k forks source link

getServerSideProps Fails to Serialize Date Object #13209

Closed JakeCooper closed 4 years ago

JakeCooper commented 4 years ago

Bug report

Describe the bug

When passing a date over the getServerSideProps boundary, it fails to serialize the Date object. Dates are serializable, so they should be allowed through.

To Reproduce

Attempt to pass a date time through the API, like so

page/index.tsx

const Component = () => {
    return <div>Hello</div>
}

export const getServerSideProps = async (ctx) => {
    const d = new Date();
    return { props: { d } }
}

export default Component

Expected behavior

Serializing occurs just fine

Screenshots

See Stack Trace

System information

Additional context

While crude, to not have to write complex logic to determine serializability, you could replace the offending method with

const canSerialize = (obj) => {
    try {
        JSON.stringify(obj);
        return false;
    } catch (e) {
        return false;
    }
}

Stack Trade:

SerializableError: Error serializing `.user.lastLogin` returned from `getServerSideProps` in "/dashboard".
Reason: `object` ("[object Date]") cannot be serialized as JSON. Please only return JSON serializable data types.
    at isSerializable (/Users/jake/programming/Railway/frontend/node_modules/next/dist/lib/is-serializable-props.js:9:7)
    at /Users/jake/programming/Railway/frontend/node_modules/next/dist/lib/is-serializable-props.js:7:497
    at Array.every (<anonymous>)
    at isSerializable (/Users/jake/programming/Railway/frontend/node_modules/next/dist/lib/is-serializable-props.js:7:304)
    at /Users/jake/programming/Railway/frontend/node_modules/next/dist/lib/is-serializable-props.js:7:497
    at Array.every (<anonymous>)
    at isSerializable (/Users/jake/programming/Railway/frontend/node_modules/next/dist/lib/is-serializable-props.js:7:304)
    at Object.isSerializableProps (/Users/jake/programming/Railway/frontend/node_modules/next/dist/lib/is-serializable-props.js:9:219)
    at Object.renderToHTML (/Users/jake/programming/Railway/frontend/node_modules/next/dist/next-server/server/render.js:356:42)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
    at async DevServer.renderToHTMLWithComponents (/Users/jake/programming/Railway/frontend/node_modules/next/dist/next-server/server/next-server.js:660:26)
    at async DevServer.renderToHTML (/Users/jake/programming/Railway/frontend/node_modules/next/dist/next-server/server/next-server.js:807:28)
    at async DevServer.renderToHTML (/Users/jake/programming/Railway/frontend/node_modules/next/dist/server/next-dev-server.js:22:539)
    at async DevServer.render (/Users/jake/programming/Railway/frontend/node_modules/next/dist/next-server/server/next-server.js:552:22)
    at async Object.fn (/Users/jake/programming/Railway/frontend/node_modules/next/dist/next-server/server/next-server.js:402:17)
Timer commented 4 years ago

This check is necessary as we do not serialize props on the server for performance reasons. So, this check only runs in development and has you make things serializable with scalar types, meaning they'll match exact on the client.

AlexandraKlein commented 3 years ago

I'm having this issue when fetching data from Contentful on posts that have links to each other.

Re: https://github.com/vercel/next.js/blob/86160a5190c50ea315c7ba91d77dfb51c42bc65f/packages/next/lib/is-serializable-props.ts#L41

Stringifying using safe-json-stringify and reparsing fixes, but I'm hoping there is a more performant solution.

import safeJsonStringify from 'safe-json-stringify';
...

export async function getServerSideProps({ params, preview = false }) {
  const rawData = await getSlugPageProps(params.slug, 'product-page', preview);
  const stringifiedData = safeJsonStringify(rawData);
  const data = JSON.parse(stringifiedData);

  return {
    props: {
      data
    }
  };
}
icflorescu commented 3 years ago

I stumbled across the same problem and got it working with by using the superjson-next plugin. See more here: https://github.com/blitz-js/superjson#using-with-nextjs

nonoumasy commented 3 years ago

@icflorescu I installed both packages and the .babelrc file and still getting the error. Do you have any tips on how you got it to work?

import superjson from 'superjson';

//this runs in build time. don't put code here that you expect to run in browser
export const getServerSideProps = async () => {
  try {
    const data = await getTips()
    data.createdAt = await superjson.parse(data?.createdAt)
    data.updatedAt = await superjson.parse(data?.updatedAt)

    return {
      props: { data },
    }
  } catch (error) {
    console.error(error);
    throw error;
  }
}
grantsingleton commented 3 years ago

I find it very strange that we have to do this when simply reading in a Date object. I guess there is a good reason? You can do it in one line like this: let data = JSON.parse(safeJsonStringify(doc.data()))

balazsorban44 commented 2 years ago

This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.