Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nuqs/server requires react #804

Closed
boredland opened this issue Dec 12, 2024 · 12 comments · Fixed by #923
Closed

nuqs/server requires react #804

boredland opened this issue Dec 12, 2024 · 12 comments · Fixed by #923
Labels
bug Something isn't working feature/cache released

Comments

@boredland
Copy link

boredland commented Dec 12, 2024

Context

What's your version of nuqs?

"nuqs": "^2.2.3",

What framework are you using?

  • ✅ Next.js (pages router)

Which version of your framework are you using?

  next: 14.2.13 // An outdated version detected (latest is 15.1.0), upgrade is highly recommended!
  eslint-config-next: N/A
  react: 18.3.1
  react-dom: 18.3.1
  typescript: 5.6.3

Description

Apart from Frontend usage, I wanted to use my nuqs parsers to generate URLs on the server-side to be sent in emails.

For that I am trying to use a serializer on an API Route like so:

import {
  createSerializer,
  parseAsStringLiteral,
} from "nuqs/server";

export const universalQueryParams = {
  "user-menu": parseAsStringLiteral(["open", "closed"]).withDefault("closed"),
};

const serializer = createSerializer(universalQueryParams);

export const serializeUniversalQueryParams = serializer(base, values);

But sadly my Next.js-build fails, telling me:

[build:next] Failed to compile.
[build:next] 
[build:next] ./node_modules/nuqs/dist/server.js
[build:next] Attempted import error: 'cache' is not exported from 'react' (imported as 'cache').
[build:next] 
[build:next] Import trace for requested module:
[build:next] ./node_modules/nuqs/dist/server.js

Is there a trick to it? As I see it, this module is required for the cache feature, that I don't need. Would splitting up the path to allow direct imports of parsers/serializer help?

@boredland boredland added the bug Something isn't working label Dec 12, 2024
@franky47
Copy link
Member

franky47 commented Dec 12, 2024

Yeah unfortunately the cache function didn't make the cut to React 19 (it's still in canary), so we might have to move that import to a dedicated one.

Since it's a breaking change, it's unlikely to happen soon though, but we could do it the other way around: provide imports for individual server-side features, like:

import { createSerializer } from 'nuqs/server/serializer'
import { parseAsStringLiteral } from 'nuqs/server/parsers'

What do you think?

@franky47 franky47 added this to the 🪵 Backlog milestone Dec 12, 2024
@boredland
Copy link
Author

That would be perfect for my use-case!

franky47 added a commit that referenced this issue Dec 12, 2024
This allows using the serializer and the parsers in server-side code without
depending on React for the cache, as would be the case if importing
from `nuqs/server`.

Closes #804. See also discussion #717.
@franky47
Copy link
Member

That solution I proposed has been implemented in #805, could you give it a go and let me know if it works please?

pnpm add https://pkg.pr.new/nuqs@805

Note: those imports are temporary until v3 lands (no date planned at the moment). In v3, the cache will have been moved to it's own import (nuqs/server/cache), and the rest of server-side features (defs, parsers, serializer) will be available to import from nuqs/server in a framework-agnostic way.

franky47 added a commit that referenced this issue Dec 14, 2024
This allows using the serializer and the parsers in server-side code without
depending on React for the cache, as would be the case if importing
from `nuqs/server`.

Closes #804. See also discussion #717.
@franky47
Copy link
Member

@boredland I tested the imports and I'm seeing some issues with TypeScript not resolving the contents of nuqs/server/*, what's moduleResolution set to in your tsconfig.json?

@boredland
Copy link
Author

Thank you for the super quick implementation! I didn't yet have the chance to test before my Christmas break, but will surely do it as the first thing next year!

franky47 added a commit that referenced this issue Dec 27, 2024
This allows using the serializer and the parsers in server-side code without
depending on React for the cache, as would be the case if importing
from `nuqs/server`.

Closes #804. See also discussion #717.
franky47 added a commit that referenced this issue Jan 1, 2025
This allows using the serializer and the parsers in server-side code without
depending on React for the cache, as would be the case if importing
from `nuqs/server`.

Closes #804. See also discussion #717.
@franky47
Copy link
Member

franky47 commented Jan 1, 2025

Hey, happy new year!

Just as a heads-up, I've merged all the non-react-based exports under a single one, renamed to make it more obvious that it's temporary:

import { createSerializer, parseAsInteger, ... } from 'nuqs/server/temporary-react-agnostic'

It's available here:

pnpm add https://pkg.pr.new/nuqs@697736a31975c7696df524508629b4396e1e1d03

franky47 added a commit that referenced this issue Jan 9, 2025
This allows using the serializer and the parsers in server-side code without
depending on React for the cache, as would be the case if importing
from `nuqs/server`.

Closes #804. See also discussion #717.
franky47 added a commit that referenced this issue Jan 16, 2025
This allows using the serializer and the parsers in server-side code without
depending on React for the cache, as would be the case if importing
from `nuqs/server`.

Closes #804. See also discussion #717.
franky47 added a commit that referenced this issue Jan 23, 2025
This allows using the serializer and the parsers in server-side code without
depending on React for the cache, as would be the case if importing
from `nuqs/server`.

Closes #804. See also discussion #717.
franky47 added a commit that referenced this issue Jan 31, 2025
This allows using the serializer and the parsers in server-side code without
depending on React for the cache, as would be the case if importing
from `nuqs/server`.

Closes #804. See also discussion #717.
franky47 added a commit that referenced this issue Feb 1, 2025
This allows using the serializer and the parsers in server-side code without
depending on React for the cache, as would be the case if importing
from `nuqs/server`.

Closes #804. See also discussion #717.
franky47 added a commit that referenced this issue Feb 7, 2025
This allows using the serializer and the parsers in server-side code without
depending on React for the cache, as would be the case if importing
from `nuqs/server`.

Closes #804. See also discussion #717.
franky47 added a commit that referenced this issue Feb 13, 2025
This allows using the serializer and the parsers in server-side code without
depending on React for the cache, as would be the case if importing
from `nuqs/server`.

Closes #804. See also discussion #717.
franky47 added a commit that referenced this issue Feb 18, 2025
This allows using the serializer and the parsers in server-side code without
depending on React for the cache, as would be the case if importing
from `nuqs/server`.

Closes #804. See also discussion #717.
@franky47
Copy link
Member

franky47 commented Feb 19, 2025

Hey y'all, if the dependency on React is not an issue (this package is, after all, a library for React), but the cache is (eg: using React 18 or 19 but not a canary version that includes it), I have a possible fix to import from nuqs/server (without needing a new export):

pnpm add https://pkg.pr.new/nuqs@f7a3217e819564e1cd38510f824242b35c32095f

Then in your code, as it was initially:

// Import from 'nuqs/server' to skip the "use client" directive in Next.js app router server code.
// Note: other frameworks don't need this and can import straight from 'nuqs'.
import { createLoader, createSerializer, parseAsInteger /* etc..*/ } from 'nuqs/server'

This doesn't solve wanting to, say, parse search params in an isolated, React-free JS backend web framework (like Fastify, Hono, Express etc), but I feel like this kind of use-case might be a tangent that #805 could focus on, rather than requiring everyone else to rewrite their imports.

@alylim
Copy link

alylim commented Feb 20, 2025

I'm trying to run some tests in nextjs14 using vitest, I've tried the latest fix

pnpm add https://pkg.pr.new/nuqs@f7a3217e819564e1cd38510f824242b35c32095f

but am getting an error from

import { createSearchParamsCache } from "nuqs/server"

> TypeError: React.cache is not a function

@franky47
Copy link
Member

@alylim thanks for the feedback, you'll need to mock that cache function in tests, as even if you can import it (using React canary), I doubt it would behave the right way in a testing environment. Here's how I did it on my end, let me know if it works for you:

vi.mock('react', () => {
return {
cache<T, CachedFunction extends () => T>(fn: CachedFunction) {
let cache: T | undefined = undefined
function cachedFn() {
cache ??= fn()
return cache
}
return cachedFn
}
}
})

@alylim
Copy link

alylim commented Feb 21, 2025

@franky47 Appreciate the quick response! It still does not work on my end but I reckon it's probably something to do with how I've implemented the tests rather than an issue with nuqs.

@franky47
Copy link
Member

@alylim if the issue isn't related to the cache import not being found, feel free to open a dedicated issue or discussion with more details.

franky47 added a commit that referenced this issue Feb 21, 2025
Having `import { cache } from 'react'` caused issues when using
React 18 or 19 GA, because the `cache` function is only exported
in canary builds (which the Next.js app router uses internally,
regardless of what's in your app's package.json).

This meant importing from `'nuqs/server'` caused an import error
when done from non app-router code, like the pages router, or
API route definitions, which would fallback to the version of React
defined in the package.json (and likely a stable one).

Changing the import to `import * as React from 'react'` is what is
being highlighted in the React docs themselves, and allows to only
call the cache function when actually creating a cache object.

Closes #804, and supersedes #805.
Copy link

github-actions bot commented Mar 6, 2025

🎉 This issue has been resolved in version 2.4.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

@franky47 franky47 removed this from the 🚀 Shipping next milestone Mar 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working feature/cache released
Projects
None yet
3 participants