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.
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 linkcd /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_modulesIf 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 startingwml
, you will run into troubles such as freezing VSCode and promptingSaving 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 withnpm 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 smallnode_modules
folder.
That’s it for now.
Please if you have any questions, don’t hesitate to comment.