React Native: npm link local dependency, unable to resolve module - react-native

I am developing a button ui package for react native. I try to build an example project to test this button. The directory structure is as follows:
my-button/
package.json
index.js
example/
package.json
index.js
I try to use npm link:
cd my-button
npm link
cd example
npm link my-button
In example/node_modules/ I can see my-button symlink, VSCode also can auto complete function in my-button package.
But execute example app will show error:
Unable to resolve module my-button ...
Module does not exist in the module map or in these directories: ...
But the path in the error message is correct.
Don't know where I was wrong, or in React-Native have any special way to deal with link local dependency?
I also tried npm install file:../.. It works fine in this way, but not easy to update dependency in example/ after I edited my-button.

The npm link command doesn't work because React Native packager doesn't support symlinks.
After a little research, I discovered that there are two ways to go about it.
Use haul packager in the example app. Haul supports symlinks, so you can use npm link as usual.
Use local dependency via file:../ and then edit files in node_modules folder or reinstall every time you make changes.
I found Haul to work great for this use-case and even set-up a little starter project that also includes storybook, which is really helpful if you have many components to switch between.

Try wml (https://github.com/wix/wml)
It's an alternative to npm link that actually copies changed files from source to destination folders
# add the link to wml using `wml add <src> <dest>`
wml add ~/my-package ~/main-project/node_modules/my-package
# start watching all links added
wml start

I couldn't always make it work with yarn link. What i found extra useful is yalc:
First install it globally once forever:
npm install -g yalc
In the local library/package (i'll call it my-local-package), and run:
yalc publish
Then in your project which uses my-local-package as a dependency, run:
(if you already have added it with any other way, first uninstall it (npm uninstall -S my-lockal-package)
yalc add my-local-package
npm install
If my-local-package is a native module, then run react-native run-android to link the dependency. (or run-ios)
If you make any change in the my-lockal-package, then:
cd path/of/my-local-package
yalc push //updates the local package
cd path/to/my-project
npm install
react-native run-android (or run-ios)
In case the update hasn't been applied, try to cd android && ./gradlew clean && cd .. and then rerun: react-native run-android.

I'm having the same issue while developing a native module wrapper around an existing native SDK. At first I followed #aayush-shrestha's suggestion to install the package locally. Like this:
npm install ../<package-folder> --save
This works as long as I reference the module via NativeModules. Import it:
import { NativeModules } from 'react-native';
And then access a module called ActualModuleName like this:
NativeModules.ActualModuleName
But it fails when I attempt to import the module by name:
import { ActualModuleName } from 'react-native-actualmodulename'
To make that work I had to first pack the package. Run this in the package's root directory:
npm pack
This generates a gzipped tarball:
react-native-actualmodulename-1.0.0.tgz
Now install that in your app:
npm install <path/to>/react-native-actualmodulename-1.0.0.tgz
An enormous downside to this is that you have to re-pack the package every time you make a change to the module. The only workaround I know of is to modify the package's files in node_modules directly and then copy those changes back to your repo when you're done.
But the upside is that your app's source can import ActualModuleName the same way you'll import it once it's released via npm; no environment-specific code necessary.

You can use npm link using Metro. Just add the source folder of the linked package to watchFolders in your metro.config.js.

Ran into the same problem. While I could not make npm link work as it should, I worked around it by installing the local package in the project folder
npm install ../<package-folder> --save
This will install the package like a regular package but from the local folder.
The downside is that the changes you make on the package will not be reflected. You will have to npm install after every change.

Change your package.json
//...
"dependencies": {
//...
"my-button" : "file:../"
},
//...

I also came across this problem. After visiting the below link, I came to know that react- native does not support symlinks.[Click here][1]
However, I have solved this by adding these lines in the metro.config.js file. Please replace your_module_name with your module name.
const path = require('path');
const thirdPartyPath = path.resolve(__dirname + '/../your_module_name/'); // Path of your local module
const thirdParty= {
'your_module_name': thirdPartyPath,
};
const watchFolders = [ thirdPartyPath];
module.exports = {
// existing dependencies
resolver: {
thirdParty,
},
watchFolders
};

I ran into the same problem.
I tried to install a local module using npm, and kept running into the issue of not being able to resolve the module, even though I could see the folder in node_modules and autocomplete of class and method names worked.
I was able to bypass it by installing the local library using yarn instead of npm after seeing this open issue on github. Issue was opened September 2020 and no comment from Facebook as of yet.

This work for me:
step 1 go to package:
npm link packageNameHere
This will link this package to global node_module
step 2 go to directory which you want to use this package and run these
npm link pathToPackageDirectory
npm install pathToPackageDirectory
ex: npm link ~/myDemoPackage
This will link global node_moudle to this project
If you want to import package to file, USE FILE PATH INSTEAD OF PACKAGE NAME !
ex:
my package name is stripe-api-helper. my code are in src/index.ts
then I need to resolve like this:
import { postStripe, Item } from '#aliciaForDemo/stripe-api-helper/src'
if u use '#aliciaForDemo/stripe-api-helper' it will fail.

Could never get my own environment working using any other suggestions, but found a hack that works well (though not ideal) that can be easily set up in just a few lines of code and without changing your RN project configuration.
Use fs.watch for changes recursively in the directory where you're working on your library, and copy the updates over whenever there's been a change:
import fs from 'fs'
const srcDir = `./your-library-directory`
const destDir = `../your-destination-directory`
fs.watch("./src/", {recursive: true}, () => {
console.log('copying...')
fs.cp(srcDir, destDir, { overwrite: true, recursive: true }, function() {
console.log('copied')
})
})

For those still looking for a simple solution without other dependency, try this:
yarn --version
1.21.1
npm --version
6.13.4
Install in project root
cd my-button
yarn install or npm install
register linking in my-button
yarn link or npm link
Install example project
cd example
yarn add ../ or npm add ../
link to my-button
yarn link my-button or npm link my-button
complete pod installation (if necessary)
cd ios
pod install

Try to run
npm run watch
inside the button package. Currently, I'm using this to apply changes from the library to my main project. Please let me know if it works!

Related

How to create build for forked React Native npm package

I forked a React Native npm library react-native-calendars to make some changes to it. I now want to implement these changes in my project. I have installed it in my project using:
npm i git+<my_forked_git_repo_url>
This successfully added the package to my node_modules, however I still get an error in my code when I try and import react-native-calendars saying Cannot find module. After doing some research I found (here) that I must create a build using npm run build and add it to the forked repository.
However, when I run npm run build it creates a build directory in my ios/ directory (since I am targeting iOS). Is this expected, or should I have a new build/ directory in the root directory? The contents of this build/ directory include a ...-buildRequest.json, ...-desc.xcbuild, ...-manifest.xcbuild, ...-targetFile.txt, and a BuildDescriptionCacheIndex-....
You could:
install the original package
paste your changes into the package's code in node_modules
install patch-package if you don't already have it (follow the instructions here)
run npx patch-package react-native-calendars
This will create a diff between the original package and your changes. Then your changes will be applied every time you run yarn or npm.

react-native-twitter-lite: Error: Unable to resolve module 'crypto'

I have followed the instructions to install react-native-twitter-lite via npm page ....as per below:
npm install twitter-lite
....then on app.js:
import Twitter from 'twitter-lite';
const twtClient = new Twitter({
consumer_key: 'xxxx',
consumer_secret: 'xxxx',
});
...I get error Unable to resolve module crypto from node_modules\twitter-lite\dist\twitter.js: crypto could not be found within the project
...even though I can see that the file node_modules\twitter-lite\dist\twitter.js exists
The issue might be that cryptojs is missing from your dependencies (not installed in your app), but react-native-twitter-lite still need it to run for security. You surely have the twitter.js but not the crypto.js. Cryptojs is used by twitter-lite to cypher and encrypt data. You may choose to use Nodejs's crypto module or react-native's build-in cryptojs. I always choose the later one for a more native behavior. For that, simple run
npm install react-native-crypto-js --save.
The first time I run into this issue this source helped me understand.
This happens to me, most likely when installing a new package to my project, I didn't try to install react-native-twitter-lite , but my general approach is :
Try to install the missing module yourself , in your case, install Crypto
Delete node_modules and install the dependencies again, run rm -rf node_modules && npm install
run your project npm start and then npm run android && npm run ios
If you install native module you will need to rebuild your app. It’s jut hot reloadable.
If that’s not your issue, but you’re using typescript, you may be missing a dependency that can fortunately be resolved using:
npx typesync
Are you using Expo or Xcode/Android Studio? If Expo, note that Expo handles a Bare and a Managed workflow. If you are using a managed workflow you may have these issues since Expo is managing native modules for you so you may want to check if Expo has a similar dependency to what you’re using, otherwise you may want to eject from Expo.
If developing for iOS, you may also want to check if you’ve installed the pods you need. You can do this using the following:
npx pod-install from root of project directory (likely same directory as package.json)
All else fails:
rn -rf node_modules
npm install && npx pod-install
(If usingTypescript also try npx typesync)
If developing for Android, make sure you add necessary code on gradle file, can be pasted anywhere (likely in docs)

Not finding relative modules on build when linked over "npm link xyz"

When running npm run serve, my VueJS projekt (Vue 2.6.11) running webpack is not finding my locally changed node module.
If i install it normally, it works (of course) and i see the changes i made in it, in the node modules folder of the project that linked it - so the link itself should be fine.
I linked it by using "npm link" in the project i want to link (i ran the build before) and then using "npm link [name]" in my main project.
The import i'm using in the main.js looks like this:
import [module-name] from '[module-name]'
just as it did when i had it installed regularly.
I also changed the settings of webpack by doing this:
module.exports = {
configureWebpack: {
resolve: {
symlinks: false //npm link
},
...
because the documentation of vue stated (for version 2, the new version has information about chainWebpack in it), that links won't work otherwhise as they're not resolved without it. still, this is the output on npm run serve:
This dependency was not found:
* [module-name] in ./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/views/CommentWriteArea.vue?vue&type=script&lang=js&
To install it, you can run: npm install --save [module-name]
(with the correct name in it of course)
Other solutions like installing the local version or forking the repository are not an option. It has to be linked for my use case

How to download and import node modules from github manually without npm, and install it in the React Native project?

In my project, we use react-native-azure-ad plugin. The problem is, this plugin at npm is outdated and use a deprecated way of accessing webview which has already been extracted from react-native to react-native-webview.
When I browsed the github page and observe the source code there, it looks like the code on the github is already updated to use react-native-webview, which lead me to believe that the npm package is not updated by the author to follow the github version.
There's only one way to fix this, that is by downloading the module directly from github and import it manually. The problem is, I only know how to import the module from installing by npm.
Currently, this is the basic folder structure:
Root
- node_modules
- src --> the app source code
I want to put the module like this:
Root
- node_modules
- node_updates
- react-native-azure-ad
- src
And I want to still be able to import it like this:
import {ReactNativeAD, ADLoginView} from 'react-native-azure-ad'
Of course I will remove the react-native-azure-ad from package.json and reinstall the node_modules afresh beforehand.
Is this possible?
I'm hoping that I don't have to rely on relative path like:
import {ReactNativeAD, ADLoginView} from '../../../node_updates/react-native-azure-ad'
I have seen some answers like this, but this requires me to use relative path to import.
using npm:
npm install <git-host>:<git-user>/<repo-name>
or
npm install <git repo url>
when using public git repo.
using yarn:
yarn add <git remote url>
or
yarn add <git remote url>#<branch/commit/tag> when you need specific branch or etc.

NPM local dependency WITHOUT copying

To make development easier it's possible to specify local NPM dependency:
{
"dependencies": {
"mylib": "file:/projects/mylib"
}
}
The problem is that you required to do npm install and the mylib will be COPIED to the node_modules. So if you change mylib you need to run npm install again.
I wonder if there's a way to do the same but as a link not as a copy, so it will be the live version of the package and any change would be instantly visible?
To avoid using the npm link command, which works creating a symlink in the global npm folder, you can try using the npm-file-link package. It works modifying the original dependency by one to the local package using the "file:" npm feature, and you can link or unlink at a time all packages you want, whenever they are all under the same folder.