Skip to content

Instantly share code, notes, and snippets.

@LukasKalbertodt
Last active June 27, 2023 13:42
Show Gist options
  • Save LukasKalbertodt/382cb53a85fcf6e7d1f5235625c6f4fb to your computer and use it in GitHub Desktop.
Save LukasKalbertodt/382cb53a85fcf6e7d1f5235625c6f4fb to your computer and use it in GitHub Desktop.
Deduplicating React dependency when `npm link`ing a library for local development

Setup

You want to do the following:

  • Put some parts of your app into a library (containing React components).
  • Already test your library with your app before publishing to NPM.

So you use npm link inside your library folder, and then npm link mylib in your app folder. This creates a symlink in app/node_modules/mylib to /path/to/mylib. In the mylib folder there is a node_moduls, too, of course. And it includes react. After all, you also want to test the library in isolation and for that you need React.

Problem

With the above setup, react exists twice: app/node_modules/react and app/node_modules/mylib/node_modules/react. As app/node_modules/mylib is a symlink, NPM's normal deduplication fails here. The result: React is added to the output bundle twice. This is a problem for React hooks, even if it's the exact same React version! You will see this error:

Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:

  1. You might have mismatching versions of React and the renderer (such as React DOM)
  2. You might be breaking the Rules of Hooks
  3. You might have more than one copy of React in the same app

Solutions

For one, react should not be in the dependencies, but in the peerDependencies of your library. And optionally in devDependencies.

Symlink mylib/node_modules/react to app/node_modules/react

This is the solution you commonly find on the internet. You remove the mylib/node_modules/react folder and then instead do ln -s app/node_modules/react mylib/node_modules/react. That way the dependency gets deduplicated correctly.

The problem is that this is super annoying and you have to constantly adjust this. If you want to test the library in another app, you have to adjust; if you do some other npm install, you might have to recreate the links.

Use webpack resolve alias

If your app uses webpack, you can add the following to the config:

resolve: {
  alias: {
    "react": path.join(__dirname, "node_modules/react"),
  },
},

Adding this alias takes precedence over the normal module resolution. So this might lead to some weird dependency problems down the line. Just be aware of that!

With that disclaimer out of the way: it works and I think it's save to just commit it to the apps repository.


Links

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