next-superjson-plugin
next-superjson-plugin copied to clipboard
Support of non-default object types
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.
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:
- rustup default stable
- rustup target add wasm32-wasi
- cargo prepublish --release
- yarn prepare
- yarn prepack
- yarn link
- update my app's next dependency to match next canary version, yarn install
- yarn link next-superjson-plugin in my app
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...
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.
Any updates on this, @orionmiz? It's a huge blocker for me with upgrading to the app router.
any updates on this @orionmiz?
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 🤷♂️