I’m trying to use react navigation 5 in my Krell RN app, however, I’m having difficulties loading it in my cljs files. On their “Getting started” page, they say that we have to use:
import { NavigationContainer } from '@react-navigation/native';
I’ve tried to replicate this as follows in cljs:
(ns my-app.core (:require ["@react-navigation/native" :refer [NavigationContainer]]))
But NavigationContainer
just ends up being undefined/nil.
If I run
(require '["@react-navigation/native" :refer [NavigationContainer]])
from the REPL, I will get
Unexpected error (IllegalArgumentException) compiling at (REPL:1).
Don't know how to create ISeq from: java.lang.Character
I’ve also tried the following:
(js/require "@react-navigation/native")
But this also returns nil.
Any ideas what I am doing wrong here?
For the installation of react navigation, I have followed their instructions:
npm install @react-navigation/native
npm install react-native-reanimated react-native-gesture-handler react-native-screens react-native-safe-area-context @react-native-community/masked-view
@michael.w.jung did you check if you need to import $default
there's no magic way us to detect that you need to look at the library and see how it's exported
@dnolen You mean like this?
(ns my-app.core (:require ["@react-navigation/native$default" :refer [NavigationContainer]]))
This doesn’t work either. Also, as we import it with curly braces in JS, it shouldn’t be a default export, right?
I don’t know much about these things, though...@michael.w.jung you need to know about 🙂
I’m using this library, with shadow-cljs, and it works. I’m not saying that it’s a krell/shadow-cljs thing. It’s probably something to do with your setup… If you want to see what is available when you require a given library, require it in the REPL:
(require "@your-lib")
If you don’t, then something went wrong upstream.examine the the library, see if exports default and something else
@michael.w.jung also (js/require "@react-navigation/native")
if that doesn't work as you said above then something else is probably wrong
oh sorry - but you can't do that anyway
React Native is not Node.js you have to understand this
if Metro can't see it - you cannot require it
Metro is never going to see your ClojureScript files - so that will never work
To avoid issues like you have to understand what Krell must do to satisfy Metro
1. Compiling your project will detect Node modules - this gets dumped into a file that Metro does see in the output directory
2. If your Node import isn't in that file - it's never going to work
look at output-dir/npm_deps.js
It seems to be there:
module.exports = {
npmDeps: {
"react-native": require('react-native'),
"react-dom": require('react-dom'),
"@react-navigation/native": require('@react-navigation/native'),
"react": require('react') }
};
so
if it's there then
A) it was in node_modules
... good
B) Krell saw it ... good
so you're running out of possibilities of what could be wrong
did you reload your RN app? new npm dependencies cannot be hot-reloaded or REPL require'd in without being there by the initial load first
right there's absolutely nothing dynamic about Metro
you have recompile ClojureScript & reload the entire app if you import something from node_modules
(for the first time)
node_modules/@react-navigation/native/lib/module/index.js looks like this:
export * from '@react-navigation/core';
export { default as NavigationContainer } from './NavigationContainer';
...
So no default export if I understand this correctlyYes, I think I reloaded / rebuilt everything.
I threw away the whole target directory and reran clj -M -m krell.main -co build.edn -c
another way to debug is the edit index.js
and console.log
this library that you're trying to use
there's nothing especially magical about the way Krell works
whenever you're done debugging you can always restore index.js
by running a compile
Ok, I added the following to index.js
import { NavigationContainer } from '@react-navigation/native';
console.log(NavigationContainer);
console.log(typeof(NavigationContainer));
console.log(NavigationContainer === undefined);
The metro output says:
{"$$typeof": Symbol(react.forward_ref), "render": [Function NavigationContainer]}
object
false
So to me this looks like it works in JSok - so now fix up your :require
to the way you originally had it
now if you look at the generated JS for that namespace you should see something that looks sensible
the one magic Krell trick here is this
there is no such thing as dynamic require in Metro - so we just monkey patch a global JS require
function that will return the library then you invoke it
this is how you can get a handle on modules and assets even though Metro never saw ClojureScript
@michael.w.jung before you go look at though
console logging the npm_deps.js
import in index.js
is probably more useful - it's a JS object that will be used by ClojureScript to "import" those libraries
if somehow the library is null in there - then of course it can't work
Very odd. Now the library is no longer in npm_deps.js
...
so this would be source of the bug if there is one
if it disappears from there - of course it won't work
but npm_deps.js
will only get rewritten if you somehow run another compile
I deleted the target folder and reran clj -M -m krell.main -co build.edn -c
. Still gone.
here's the one other thing
your ClojureScript require cannot be in some random file outside of the entry point dep graph
i.e. a.core
is the app entrypoint and you have some side file b.core
which imports Node library
which is never required by a.core
Ok, that’s why it was gone. I commented out some stuff before and it no longer was in that dependency graph. It is back now that I fixed this.
you are now a Krell expert 🙂
there's no other rules than the above
Well, I certainly don’t feel like one 😄
It seems to work now
I have no idea what I changed. It probably really was because I removed the require of the file that imported the lib when I tried to debug the issue.
✨
Thank you very much for your help @dnolen. I was about to give up on this. Much appreciated!
No problem
But hopefully the above shows Krell works in a way intentionally to make debugging issues relatively straightforward
And I haven’t seen a library that can’t be used
Yes, it definitly did. I specifically chose Krell because it seemed rather simple and straightforward. I did some experiments with re-natal and expo in the past, but that was a complete mystery to me. I’m still pretty much a newbie in both CLJS and JS.
I have added another library to my project. This time with a default export. And again, I was having quite some trouble until I finally managed to get it to run.
I think I’m still missing a piece of the picture: When I add a new dependency, which steps do I need to take?
I thought I have to do this:
1. npm add my-lib
2. Require the library in cljs
3. Recompile using clj -M -m krell.main -co build.edn -c
4. Restart the Android app
But I think this wasn’t enough. I also did the following things in some order I don’t remember:
• Delete and rebuild the target
dir
• Restart metro with npx react-native start
• Reinstall the Android app with npx react-native run-android
(I’m not building for iOS at the moment)
Metro also has caching problems - but otherwise I don't think any of those other steps should be necessary
definitely have gotten into funny situations w/ Metro which have nothing to do w/ Krell that requires a whole cycle
whatever is on disk is the truth - and if it's still not working, I think the likelihood the problem is in Krell is quite low
but happy to take a specific set of steps to reproduce if you can come up w/ them - I dev on Android less so maybe it's spottier there