Linking Local Packages in React Native the Right Way

You Don’t Need to Waste 12+ Hours Figuring Out Why Your Local Package Exists but Metro Bundler Complains That It Does Not.

Ali El Majdaoui
3 min readOct 16, 2021

Sometimes we need to locally test our own react-native packages before publishing them to the npm registry. We can simply do that with the npm link command:

cd /path/to/my-awesome-package
npm link
cd /path/to/my-project
npm link my-awesome-package

And you have now the package available to import into your project.

const { someMethod } = require('my-awesome-package');
// ... or
import { someMethod } from 'my-awesome-package';

This is the right approach when it’s about a React web, Electron, etc… project. But, this won’t work if you need to link a package to a React Native project and it will throw this error:

error: Error: Unable to resolve module my-awesome-package from /Users/mac/MyReactNativeApp/src/App.tsx: my-awesome-package could not be found within the project or in these directories:
node_modules
../../node_modules

If you are sure the module exists, try these steps:
1. Clear watchman watches: watchman watch-del-all
2. Delete node_modules and run yarn install
3. Reset Metro’s cache: yarn start — reset-cache
4. Remove the cache: rm -rf /tmp/metro-*

Please don’t do anything of those 4 steps above, it’s a real waste of time.

Why?

npm link creates a symlink from the package to your project’s node_modules folder. In React Native, symlinks are not supported (Proof 😄). It’s because of the way the Metro bundler works.

1. Resolve More Node Modules Paths with Metro

Yes, Metro knows that we can’t symlink 😲 and it provides us an option to locate third-party dependencies if they are installed in a different location outside of our project folder.

To do that, open the metro.config.js that’s located in your root React Native project folder and make sure it has the property nodeModulesPaths inside the property resolver . Your metro.config.js file should look something like:

⚠️ Please make sure to close the Metro bundler then restart your app whenever you make a change to themetro.config.js file.

At this point, your local package should be imported into your React Native project without any issues.

But… we are missing an imported feature here! Try to change your package code and won’t see your React Native app reloading. That’s because the package is not being watched for changes.

To do that, we need to add an extra option to the Metro configurations.
Simply add the property watchFolders to the exports object. Your metro.config.js file should look something like:

Another little issue here is that you will still see that your IDE (VSCode in my case) complains that it can’t find the module you are importing!

“Cannot find module ‘my-awesome-package’ or its corresponding type declarations.ts(2307)”or if you are using Flow:“Cannot resolve module `my-awesome -package`.Flow(InferError)”

We can simply solve this by using npm install command:

npm install /Users/mac/my-own-packages/my-awesome-package

If Flow still complains, restart the client. (Open VSCode command palette and run the command: Flow: Restart Client)

et voilà ! You should be using your local package in your React Native app without any issues.

You can read more about Configuring Metro.

2. Run Copy/Paste on Autopilot (Seriously 😅)

Copying a package inside any Node.js project works! But it’s very annoying to keep doing the same whenever you make a change to a package’s file.

Hopefully, there’s a package to help us copying changes whenever we change something in our package. Please meet wml .

Usage:

First, we need to add a link:

wml add /path/to/my-package /path/to/my-react-native-project/node_modules/my-package

wml will not start listening to changes until you start it by running:

wml start

Things to Consider When Using WML

  • Make sure your package node_modules folder is not very big, otherwise, when starting wml , you will run into troubles such as freezing VSCode and prompting Saving dirty editors is taking longer than expected… whenever you want to close/reload it.
  • Pack your package with npm pack , move it to another location and install it with npm install --production this will make sure to install only production dependencies which will make the project looks more realistic to the future published version of it on the npm registry. This guarantees a small node_modules folder.

That’s it for now.

Please if you have any questions, don’t hesitate to comment.

--

--

Ali El Majdaoui

Programmer? Developer? Coder? Engineer? ...call me whatever you like