next-superjson-plugin icon indicating copy to clipboard operation
next-superjson-plugin copied to clipboard

Support of non-default object types

Open kdubb1337 opened this issue 2 years ago • 5 comments

Verify Next.js canary release

  • [X] I verified that the issue exists in the latest Next.js canary release

Describe the bug

Non-default object types aren't picked up and you get the following error:

  • error node_modules/.pnpm/[email protected]/node_modules/superjson/dist/transformer.js (184:0) @ Object.eval [as untransform]
  • error Error: Trying to deserialize unknown custom value at Array.forEach () null

I followed the suggested custom recipe format and inject it near the root of my app:

import SuperJSON from 'superjson'

export function registerCustomTypes() {
  // Register Decimal as a custom type
  // Ref: https://github.com/blitz-js/superjson/pull/159/files
  SuperJSON.registerCustom<Decimal, string>(
    {
      isApplicable: (v): v is Decimal => Decimal.isDecimal(v),
      serialize: (v) => v.toJSON(),
      deserialize: (v) => new Decimal(v),
    },
    'Decimal',
  )
}

Expected behavior

The next-superjson-plugin should function the same as superjson when called directly.

Reproduction link

No response

Version

^0.5.7

Config

export default {
  reactStrictMode: true,
  swcMinify: true,
  images: {
    domains: [],
  },
  experimental: {
    appDir: true,
    serverComponentsExternalPackages: ['@prisma/client'],
    swcPlugins: [['next-superjson-plugin', {}]],
  },
}

Additional context

I was able to follow the example from Superjson on adding custom types and can use superjson directly to serialize and then parse it back to the original object, but when using data-superjson it doesn't work and I get the error above.

kdubb1337 avatar May 10 '23 21:05 kdubb1337

We've also got a need for Decimal.js support (and some other internal/misc types). Feels like we need some sort of "bring-your-own-superjson" support where we can provide the instance or ensure our type registrations happen before this plugin uses superjson. I tried to hack this into the plugin with this commit. That built and I was able to yarn link my custom build into our app but I was getting memory access errors and an error about not being able to find the React module for some reason.

I'm not a rust guy, but steps I used to build were:

  1. rustup default stable
  2. rustup target add wasm32-wasi
  3. cargo prepublish --release
  4. yarn prepare
  5. yarn prepack
  6. yarn link
  7. update my app's next dependency to match next canary version, yarn install
  8. yarn link next-superjson-plugin in my app

jon-ressio avatar Jul 13 '23 15:07 jon-ressio

I'm migrating a Pages router based NextJS application to the new App router and I'm facing the same issue.

In the Pages router application I registered custom types (Decimal.js) successfully in _app.tsc like documenten here: https://github.com/blitz-js/superjson#decimaljs--prismadecimal

SuperJSON.registerCustom<Prisma.Decimal, string>(
  {
    isApplicable: (v): v is Prisma.Decimal => Prisma.Decimal.isDecimal(v),
    serialize: v => v.toJSON(),
    deserialize: v => new Prisma.Decimal(v),
  },
  'decimal.js'
)

For the App router I did the same in layout.tsx (?? correct ??) but then when including a component like:

<PersonTable persons={persons} data-superjson />

it gives me the Error: Trying to deserialize unknown custom value as well...

image

Does the next-superjson-plugin not support the App router with custom types yet? This is unfortunately blocking me from upgrading to the App router.

marceloverdijk avatar Jan 27 '24 18:01 marceloverdijk

Any updates on this, @orionmiz? It's a huge blocker for me with upgrading to the app router.

aleehedl avatar Apr 02 '24 06:04 aleehedl

any updates on this @orionmiz?

jacob-minca avatar Aug 01 '24 00:08 jacob-minca

If anyone else stumbles upon this issue, i was able to solve it by ensuring i register the serializer/deserializer in both client and server components manually.

-----in server component (in my case, layout.tsx)----

import { firestore } from "firebase-admin";
import SuperJSON from "superjson";

SuperJSON.registerCustom<firestore.Timestamp, string>(
  {
    isApplicable: (v): v is firestore.Timestamp =>
      v instanceof firestore.Timestamp,
    serialize: (v) => v.toDate().toISOString(),
    deserialize: (v) => firestore.Timestamp.fromDate(new Date(v)),
  },
  "Timestamp"
);

-----in client component (in my case, providers.tsx, rendered in the layout component)----

'use client'
import {  Timestamp } from "firebase/firestore";
import SuperJSON from "superjson";

SuperJSON.registerCustom<Timestamp, string>(
  {
    isApplicable: (v): v is Timestamp => v instanceof Timestamp,
    serialize: (v) => v.toDate().toISOString(),
    deserialize: (v) => Timestamp.fromDate(new Date(v)),
  },
  "Timestamp"
);

i couldn't find anything about it in the docs, though it is an expected requirement 🤷‍♂️

nojuskybartas avatar Aug 01 '24 07:08 nojuskybartas