The ‘Your JavaScript code tried to access a module that doesn’t exist’ error, Expo Go, and development builds
If you are developing a React Native app for iOS using Expo with the Expo Go app, and the above error strikes fear and confusion in your heart (like it did with me), keep reading.
I got the dreaded above error, and it took me a while to ‘get’ what was behind it. So this post is to collect my findings around it and share the resolution.
If you just want the quick resolution, here it is: follow the steps in this great tutorial by RevenueCat, replacing the react-native-purchases library they talk about with whatever one you’re trying to get running. At the end you’ll end up with a ‘dev build’ on your phone playing the same role as Expo Go did before, allowing you to test your app including the library that first caused the ‘Module that doesn’t exist’ error.
You’re welcome.
But if you are still worried even after following the steps from that article that your Expo Go days are now gone forever, read on.
A note for context: mobile dev is not the main thing I do, just a side hobby — and I have never in my life developed anything in XCode or with ‘native’ iOS code (Swift, Objective C), only React Native with Expo. And I’m planning to keep it that way for as long as I can. So if you are more experienced with iOS development or the ‘normal’ React Native ecosystem where you combine React Native CLI with XCode and Android Studio etc etc, then this post probably is waay too beginner level and not for you.
Libraries for React Native can be ‘pure Javascript’ or ‘leveraging native functionality’
Here is the first key thing to know: when using a library in your React Native / Expo code base, it can have two ‘flavours’: either it is a pure ‘Javascript’ library, or one that leverages ‘native’ code under the hood.
The libraries that rely on native code are associated with something called ‘Native Modules’, and also it has something to do with ‘Pods’ and ‘linking’. But the ‘pod’ and ‘linking’ stuff isn’t needed anymore because it’s built-in with later versions of React Native.
Here is some more reading on Native Modules if you’re interested:
Native Modules Intro · React Native
Now, here’s what makes all the difference in practice between these 2 types of libraries: libraries relying on native code need to be built after being included in your codebase, before they can work. If your app was not ‘built’, you can get the above error.
The Expo SDK, native libraries and Expo Go
Some of this ‘native’ functionality is things like accessing your phone camera, calendars, push notifications etc. But wait a minute. While coding your app with Expo, you might have been using these and still got local dev working just fine on Expo Go without any ‘building’ step needed! What gives?
The answer is these libraries are already built in for Expo Go app. They are ‘official’ libraries of the Expo SDK. Actually, doing this is probably one of the key ideas that started the whole Expo project in the first place.
But other such libraries, coming from third parties, like for instance the Revenue Cat React Native SDK, are not built in to Expo Go, and so you’ll have to do some building yourself.
Developer Builds and Expo Dev Client
Using libraries that depended on native code used to mean game over for that sweet Expo+Expo Go workflow. It required ‘ejecting’ and moving to the ‘bare’ workflow, something that all sounded like going back to the beginning and too much of a hassle to me, so I’ve never gone there. (did I mention I’m not a professional mobile developer yet?)
BUT, it turns our that those scary days are over! A few years ago, the Expo team recently ‘saved’ their great workflow with the expo dev client (aka ‘Custom Development Client’) feature.
An Expo Dev Client is basically your own ‘mini Expo Go’ app, specifically for the Expo project you are working on, with not just the Expo SDK libraries you are using, but also any third party native-dependency libraries ‘built in’!
So this is the gist:
To develop with Expo using third-party libraries that rely on native code/modules, you need to create a custom developer build + the expo-dev-client dependency in your project, instead of Expo Go.
The good news is, if I understand correctly, you don’t need to create a new such build to see each code change, just once for ‘baking in’ your third-party libraries. And after that, this build becomes your new ‘Expo Go’, with the real time updates every time you change code etc. Javascript-developer-friendly workflow saved!
UPDATE Sep 4: just found this amazing page + video from the Expo team, which lines out these same conclusions very nicely:
https://docs.expo.dev/develop/development-builds/create-a-build/
Forum posts, guides and articles
After running into the error from this post’s title, and being in the position of ‘coming back’ to Expo after having played with it a few years earlier and then no more, this recent article on the ‘bigger picture’ by ReTool is what made some things click:
Putting the Expo vs React Native debate to rest
Among other things, it nicely lays out the relation between ‘EAS’ and other parts of the Expo landscape.
Creating your developer build
You can apparently also build a ‘developer build’ without using eas at all, using XCode:
How to build an iOS Expo App without using EAS Build
But for now I’ll stick with eas and keep avoiding XCode wherever I can. Free tier of eas still seems pretty generous after all:
Expo Application Services (EAS) Pricing
And what’s even nicer, even if I hit the free limit, the next plan they have is ‘pay as you go’, so still no need for signing up to some monthly plans or anything. Thanks Expo team!