Skip to content

fix: Import React.cache only when needed#923

Merged
franky47 merged 1 commit intonextfrom
fix/804-react-cache-import
Feb 21, 2025
Merged

fix: Import React.cache only when needed#923
franky47 merged 1 commit intonextfrom
fix/804-react-cache-import

Conversation

@franky47
Copy link
Member

@franky47 franky47 commented 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, an API route definition, or a non-Next.js framework, which would fallback to the version of React defined in the package.json (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.

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.
@franky47 franky47 added this to the 🪵 Backlog milestone Feb 21, 2025
@vercel
Copy link

vercel bot commented Feb 21, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
nuqs ✅ Ready (Inspect) Visit Preview 💬 Add feedback Feb 21, 2025 4:22pm

@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 21, 2025

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

commit: 12ec159

@franky47 franky47 enabled auto-merge (squash) February 21, 2025 16:24
@franky47 franky47 merged commit 0c955ce into next Feb 21, 2025
29 checks passed
@franky47 franky47 deleted the fix/804-react-cache-import branch February 21, 2025 16:25
@github-actions
Copy link

github-actions bot commented Mar 6, 2025

🎉 This PR is included in version 2.4.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

@rik-iso
Copy link

rik-iso commented Mar 6, 2025

web:build | ../../node_modules/.pnpm/nuqs@2.4.1_next@14.2.23_@babel+core@7.24.6_@opentelemetry+api@1.9.0_react-dom@18.3.1_react@18_254swa4g7i3oqurqrbun7hl3xa/node_modules/nuqs/dist/server.js
web:build | Attempted import error: 'cache' is not exported from 'react' (imported as 'React').

web:build | Import trace for requested module:
web:build | ../../node_modules/.pnpm/nuqs@2.4.1_next@14.2.23_@babel+core@7.24.6_@opentelemetry+api@1.9.0_react-dom@18.3.1_react@18_254swa4g7i3oqurqrbun7hl3xa/node_modules/nuqs/dist/server.js
web:build | ./app/features/search/(sections)/products/hooks/filters/getProductSearchFilterParsers.ts
web:build | ./app/features/search/(sections)/products/hooks/filters/useProductSearchQueryStates.ts
web:build | ./components/page/marketplace/MarketplaceProducts.tsx

still seeing this issue on 2.4.1

@franky47
Copy link
Member Author

franky47 commented Mar 6, 2025

@rik-iso what's your setup?

@franky47 franky47 removed this from the 🚀 Shipping next milestone Mar 6, 2025
@rik-iso
Copy link

rik-iso commented Mar 6, 2025

This might be operator error but I'm confused how to fix it.

The specific file getProductSearchFilterParsers is importing:

import { parseAsArrayOf, parseAsInteger, parseAsString, parseAsStringEnum, parseAsStringLiteral } from 'nuqs/server'

In the above crash, it's being used in a pages router page, but it also needs to be used in an app router page (we're mid-migration). Should I be importing it differently?

@rik-iso
Copy link

rik-iso commented Mar 6, 2025

(The crash actually only happens on next build and not in my dev server)

@franky47
Copy link
Member Author

franky47 commented Mar 6, 2025

Are you using the cache feature (createSearchParamsCache) anywhere at all?

I'll try and reach out to the Next.js team to see if they have ideas for this kind of use-case, and I'll try and reproduce on my end in the mean time.

@rik-iso
Copy link

rik-iso commented Mar 6, 2025

Yeah I am using that cache on this property but only in the app router pages - the cache shouldn't be being used in the pages router code path.

@rik-iso
Copy link

rik-iso commented Mar 6, 2025

I'm going to see if I can refactor out the use of the cache as I think it might be mostly redundant and see if that stops the error for now.

@franky47
Copy link
Member Author

franky47 commented Mar 6, 2025

If you don't need the no-prop-drilling property of the cache, you can use a loader instead.

@rik-iso
Copy link

rik-iso commented Mar 6, 2025

Possibly found the culprit - for some reason I am doing

export type SearchQueryState = ReturnType<typeof searchQueryStateCache.all>
export const searchQueryStateCache = createSearchParamsCache(getProductSearchFilterParsers(SEARCH_DEFAULT_PARSERS))

then I am only importing SearchQueryState using import type into a pages router page... but maybe that's enough to break the build (but not dev server).

Cleaning this up to use inferParserType... it's code I wrote in early nuqs v1 days so maybe that didn't exist then or I didn't know about it 🙃 .

@rik-iso
Copy link

rik-iso commented Mar 6, 2025

nevermind, that didn't solve it sadly.

@franky47
Copy link
Member Author

franky47 commented Mar 6, 2025

Could you paste the result from running next info please?

While trying to reproduce this in the e2e environment, I managed to get the cache to compile (and partially run) in the pages router, which is definitely not supposed to happen 🙃 (ie: I can't get it to fail on next build).

@rik-iso
Copy link

rik-iso commented Mar 6, 2025

$ pnpm next info

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 24.3.0: Thu Jan  2 20:24:23 PST 2025; root:xnu-11215.81.4~3/RELEASE_ARM64_T6020
  Available memory (MB): 32768
  Available CPU cores: 12
Binaries:
  Node: 22.13.1
  npm: 9.6.7
  Yarn: N/A
  pnpm: 9.15.4
Relevant Packages:
  next: 14.2.23 // An outdated version detected (latest is 15.2.1), upgrade is highly recommended!
  eslint-config-next: N/A
  react: 18.3.1
  react-dom: 18.3.1
  typescript: 5.7.3
Next.js Config:
  output: N/A
 ⚠ An outdated version detected (latest is 15.2.1), upgrade is highly recommended!
   Please try the latest canary version (`npm install next@canary`) to confirm the issue still exists before creating a new issue.
   Read more - https://nextjs.org/docs/messages/opening-an-issue

@rik-iso
Copy link

rik-iso commented Mar 6, 2025

Please don't spend too many cycles on this right now if it's not trivial to reproduce (unless someone else reports the same issue of course) - I've worked around it. That said I'm happy to try and help repro it as much as possible if it helps!

I'm working around it for now by making a copy of the file that depends on nuqs/server and using nuqs in it, then prop drilling the right version of the method down depending if it's in app router or pages router 🙃 . It's highly possible there's something weird in our codebase (which is a bit of a frankenstein's monster of app and pages router at this point).

@franky47
Copy link
Member Author

franky47 commented Mar 6, 2025

Ahh I get the error by reproducing your exact setup (matching Node.js, React & Next.js versions). So updating some of those might solve the issue. My bet is on React, I'll see if bumping just that one to 19 solves it.

Edit: bingo, switching to React 19 did solve the issue. Which is weird because 19 doesn't export the cache, it's still in canary..

I'd like to get to the bottom of it just so that I can advise others that encounter the same issue.

@rik-iso
Copy link

rik-iso commented Mar 6, 2025

Just react? react-dom too?

I'm concerned that a React upgrade may be a herculean task on this old repo but iirc for the pages router it will stay effectively stuck to React 18?

but good to know. we're luckily burning the world and building a new app soon on Next 15/R19 so not inclined to go too deep on this if nuqs itself is fine (phew) and I have a workaround here...

Thanks so much for looking into this and for nuqs. Looking forward to adding nuqs to our new app too!

@franky47
Copy link
Member Author

franky47 commented Mar 6, 2025

It's only in the react package, though I keep both in sync with pnpm catalogs (it's in a monorepo too, getting mismatching versions across packages causes weird issues).

TIL that react@19.0.0 does indeed export the cache function, even though the docs say it's only in Canary.

@rik-iso
Copy link

rik-iso commented Mar 6, 2025

Oh I was looking for something like pnpm catalogs just the other day, thanks for showing me that! Time to get pnpm upgraded to v10.

@franky47
Copy link
Member Author

franky47 commented Mar 6, 2025

You're welcome! Just watch out for postinstall scripts not running by default in v10.

This can help (Next.js needs sharp & swc):

nuqs/package.json

Lines 35 to 43 in 0910b2d

"pnpm": {
"onlyBuiltDependencies": [
"@sentry/cli",
"@swc/core",
"cypress",
"esbuild",
"sharp"
]
},

@franky47
Copy link
Member Author

franky47 commented Mar 7, 2025

Thanks for the sponsorship! 💖

@schardev
Copy link

schardev commented May 24, 2025

I'm in the same spot as @rik-iso, we're also doing a migration from pages to app router, added nuqs to smoothen out search params handling but it's throwing the exact same cache is not exported error, even though I'm not using any server side features like createSearchParamsCache.

I want to be able to share the search params definition object between app (both server and client) and pages router so I can't just change the import from nuqs/server to nuqs. Here's a repro of the same issue. Try to build it.

EDIT: Can't update next or react to v19 just yet as the app I'm working on is legacy and doing that would require a huge effort.

@franky47
Copy link
Member Author

@schardev thanks for the repro. If you can't update to React 19 (which would be the best way to solve this), you could patch the react package to add a dummy cache export to let your build pass, see https://github.com/schardev/nuqs-issue/pull/1.

@schardev
Copy link

Adding this here for anyone who checks later - thanks for the patch, it worked like a charm 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

nuqs/server requires react

3 participants