vercel / next.js

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

Module not found: Can't resolve 'react' when importing local library with React as peerDependency #20266

Open TeemuKoivisto opened 3 years ago

TeemuKoivisto commented 3 years ago

Bug report

Describe the bug

So I often develop libraries locally with React as a peer dependency. This, however, apparently doesn't work with next.js out of the box or I guess I am supposed to do some additional plumbing to get it to work?

I assume because this works with normal React apps that this isn't a standard behavior or it should at least be well-documented. It is not nice to spend hours fixing these types of bugs. Part of the reason could be my rollup configuration for the local-module yet it baffles what I should do to fix it.

There has been some similar previous discussion #1244 #3841 yet none seem to provide a satisfying answer what is happening.

To Reproduce

https://github.com/TeemuKoivisto/nextjs-react-not-found

Expected behavior

I expect next.js to find the local-module as it can apparently do it quite well if the library is inside the nextjs-app folder.

Screenshots

React not found

System information

Additional context

matamatanot commented 3 years ago

@TeemuKoivisto ref #15569.

This enables automatic configuration of transpilation for modules resolved outside of nextjs app trough path aliases.

You can specify the baseUrl in jsconfig even if you are not using TypeScript.

TeemuKoivisto commented 3 years ago

@matamatanot Hey, thanks for answering. I am not sure what do you imply, do you mean adding the path of the local-module as an alias? I don't really want to write absolute paths (or force some specific relative path) to my tsconfig which could differ from user to user. I looked up this SO thread for reference.

Also, I updated my example to show how it should work with any old normal React app.

matamatanot commented 3 years ago

@TeemuKoivisto Do you want to import the build outputs with rollup?

If you want to leave the build to Next.js, you can do so by specifying the baseUrl in Next.js tsconfig and changing next.config.js below

https://github.com/vercel/next.js/pull/13542/files#diff-738f132ea5ea7014901c0a03052025589f4a912b25a2f470151523408fae2a3d

However, Next.js has a complex configuration using webpack, which is different from the code when using rollup. (The behavior should be identical.)

TeemuKoivisto commented 3 years ago

@matamatanot I have a local module/library which uses rollup to generate a cjs and esm modules of the TypeScript code. Importing either of them doesn't work as Next.js can't resolve react while bundling them to serve the app. I haven't touched the Next.js bundling process at all, just used rollup for the local module. I added the next.config.js you provided (with "baseUrl": ".") but it didn't change anything.

For fun I tried first installing my own library https://github.com/TeemuKoivisto/react-seo-meta-tags with yarn add react-seo-meta-tags which worked perfectly. Then I used yarn link react-seo-meta-tags which produced the same bug. Including react as a devDependency for react-seo-meta-tags allows next.js to bundle the code without crashing but this doesn't work if you use ReactDOM (as I do in my other library) since it then mysteriously crashes and complains about having two React apps.

SokratisVidros commented 3 years ago

Same issue here with Next.js version 10.0.5. Also happens with Next.js v9.5.5. Any other hacks until the permanent resolution will be greatly appreciated.

TeemuKoivisto commented 3 years ago

@SokratisVidros I found two solutions.

  1. Use the library as a git submodule so it stays always inside the next.js app folder.
  2. Use the module file path in the package.json eg "my-library": "file:../my-library",

Depending on if the library is its own git repository or not the 1. option might be a better choice. If it's just a local shared library then the file path might be the only choice. The biggest problem with that approach is that the module is installed directly, not symlinked, and therefore any updates won't show up in the eg node_modules/my-library folder. Whenever you make changes you either have to delete the lock file and the module eg rm yarn.lock && rm -rf node_modules/my-library or just delete all node_modules and reinstall. Both of them kinda suck so I would appreciate if the normal behavior with linking from anywhere in the file system worked.

louis-md commented 3 years ago

Same issue here. Any progress would be much appreciated.

TeemuKoivisto commented 3 years ago

@louis-md Actually I've noticed that Yarn workspaces work quite well with a monorepo. So I should probably edit my previous solution, that file path at least is kinda terrible. But if the library is somewhere far away in the file system, I'm not sure of any great solutions. You could try publishing it locally but that seems quite hacky.

louis-md commented 3 years ago

I found another solution: install the peerDependencies locally (I did so using install-peers-cli), and then yarn link the react folder which is inside the library's node_modules folder into the main project. The process is explained here:

https://dev.to/yvonnickfrin/how-to-handle-peer-dependencies-when-developing-modules-18fa

It worked for me, hope it'll help others solve this problem.

vladblindu commented 2 years ago

Still same problem here in march 2022. Any news. Linking is not really a solution. It's a temporary fix.

jorgebaralt commented 2 years ago

@SokratisVidros I found two solutions.

  1. Use the library as a git submodule so it stays always inside the next.js app folder.
  2. Use the module file path in the package.json eg "my-library": "file:../my-library",

Depending on if the library is its own git repository or not the 1. option might be a better choice. If it's just a local shared library then the file path might be the only choice. The biggest problem with that approach is that the module is installed directly, not symlinked, and therefore any updates won't show up in the eg node_modules/my-library folder. Whenever you make changes you either have to delete the lock file and the module eg rm yarn.lock && rm -rf node_modules/my-library or just delete all node_modules and reinstall. Both of them kinda suck so I would appreciate if the normal behavior with linking from anywhere in the file system worked.

  1. Use the module file path in the package.json eg "my-library": "file:../my-library", Worked for me, thank you 🔥
pfried commented 2 years ago

This one worked for me: https://www.npmjs.com/package/next-transpile-modules#i-have-trouble-with-duplicated-dependencies-or-the-invalid-hook-call-error-in-react

It does not have the downside of no live refresh and it works when correctly setting react as a peer dependency

espipj commented 1 year ago

Seems that link wasn't working for me... "my-library": "link:../my-library", file: does work: "my-library": "file:../my-library" Thanks @SokratisVidros 😃