I'm considering RN right now. Wondering whether to start from scratch or not. People refer to issues "ejecting" from Expo but those issues are vague and go back years.
Any concerns or experiences on your end that make it a good or bad option?
They like to do a lot of breaking changes between versions that are very painful to upgrade to. But this also applies to RN and JS ecosystem to a lesser extent.
I believe the situation with this has improved. Before EAS you needed to target one of the more recent SDK versions or you wouldn't be able to build using their services. However, if your app is new (or upgraded) enough to use EAS now then you don't get locked out of building anymore.
But still, upgrading SDK versions to stay on top of security/new features can be a burden with how many breaking changes there are.
Ejecting is no longer required with EAS (Expo Application Services) build. You can bring in your own native dependencies and still use Expo without ejecting.
I use it for the Rust (video game) companion app, using the stock libraries bundled within Expo so development is a breeze.
IMO the best thing about expo is that your native project folders pretty much becomes build artifacts, and so can be left out of your git repo.
That is great because those project folders are usually quite fragile and can easily break over time.
Before "prebuild" was introduced, you had to stick to expo-included native modules to get that advantage, and if you didn't, you had to "eject", which was hardly better than not using expo at all.
With "prebuild" you can use any native module and still have a git repo free of those fragile iOS and Android folders. It is more work setting up those modules, but it's worth it IMO.
Is there anything equivalent for Vue? I know there was VueNative and NativeScript and there is even Ionic in Vue, but haven't really seen any framework that is either dedicated to Vue or has a strong support for Vue.
The title made me think they were trying to rebrand as not being limited to React Native. I think they are instead trying to market to a wider audience by not mentioning React in their tagline, though.
Quasar+Vue (uses Capacitor as well) has worked very well for me. I used Ionic with Angular years ago and I know they support Vue now but their support wasn’t great last I looked (it’s been years, this might have changed). Quasar is Vue-only and benefits from that focus.
I believe you could do it by writing a config plugin[1] that will apply the desired config changes to the native project files.
Expo will apply the config from plugins when they are building the native app for you.
(Disclaimer: I use Expo at work for cross-platform app including web but never wrote my own plugins)
This was my main criticism as well, but not anymore.
With the "prebuild" workflow you can regenerate your iOS and Android projects anytime you need. And set up scripts for adding external libraries in the process.
It is more work to set up over just altering the native projects, but the result is rather nice.
I've never felt 100% confident that react native project folders wouldn't break for arbitrary reasons. Being able to so easily start over is very useful.
It's RN with less (or I guess different) steps, actually; you can skip the bit where you have to manage and build the native parts of your apps, even though with RN that's already minimal, manageable and works out of the box. generally.
I've used Expo going on 3 years now, their development team is incredible. There are very few reasons to use base react-native over Expo anymore; They make upgrades to new RN versions easier, can support any custom native libraries, have an awesome build service (EAS), support OTA updates, their docs are great... I could go on and on. If you're a RN dev and haven't tried out Expo in the past year I highly recommend giving it another go - its not the Expo you remember before their custom dev-client days.
I haven't used react native in years. Expo at the time felt like a shitty add-on trying to capture some part of the app development process but I didn't feel it added anything.
Sounds like I s gotten a lot better and found an actual usecase. I'll have to check them out again.
I love these real takes. I had the exact same experience trying to get into React Native and Expo, eventually just decided to write native apps if I ever get into app dev.
Yea, felt the same but haven't used react native for years either. Some concrete examples:
- Generally a poorer developer experience (bugs, bad documentation).
- Couldn't use some popular/common react native packages. It needed to be compatible with Expo, and there was an expo specific version to use the camera for example. These would have different (and more) bugs. Trying to use any unsupported packages meant ejecting, a hell that might be similar to ejecting from create react app or using craco, perhaps.
- Wasn't really adding much apart from being "all-in-one", but unfortunately each piece was sub par to the original react native.
- Unfortunately the react native docs were defaulting to suggest using Expo. They still do that now: https://reactnative.dev/docs/environment-setup. And yet developers often eject from Expo, so you'd rewrite the scaffolding of your app without expo instead of ejecting. IMHO that's quite sad to see the React Native docs still suggests Expo.
Side note: I've been using Flutter for a few years now, much better developer experience. Doesn't have code push yet, but https://shorebird.dev/ is working on it. (I am not affiliated with them).
Last time I worked with Expo, the main historical reason for ejecting (custom native modules) was all but eliminated by the config plugin system. We actually ejected at one point, but rolled back that change once we realise the plugin system could do everything we needed.
Tbh, I liked expo, but since you cannot build locally nowdays (you can eject and build, but that won't work 99% of the time, literally didn't work for me on the hello world example), I kinda just threw it in the "cool, but won't use" bucket for time beeing :/, could change in the future, but I don't know how I feel about 3d party service (EAS) building my app and holding my signing certificates (yet)
You can build locally without ejecting; just throw the --local flag on the end of your eas build command This does what EAS would do, just on your local machine. If you remove the --local flag, it will send it up to EAS to do the build.
eas build --profile develop --platform ios --local
yes, you are right, however, AFAIK you still need to be logged + have it linked to eas project (because it uses eas credentials) + this method is planned to be deprecated soon [?] (I'm 100% sure I read stuff like this when researching it like half a year ago, but cannot find it for the love-of-god atm :D, but I would like to be proved otherwise, because the build step is the only thing I disliked about expo long-term wise)
... now looking more into it, I probably mistook `npm run export` / `expo build` with `eas build --local`. Is this correct?
I think your commands are kind of muddled. By `npm run export`, I assume you are referring to `expo export`? That is responsible for bundling your app for OTA updates. `expo build` is the deprecated method for building your Expo app with the old ExpoKit native shell app. Only `eas build --local` is the actual command for locally building your app.
Perhaps the issue you're thinking about was what I linked to in my other comment?
By my own thinking, I believe it's quite unlikely that Expo will ever manage to actually totally remove support for local builds, even though they probably will never encourage it; as otherwise, its really quite impossible to debug native builds, and indeed local builds are Expo's recommendation for debugging such issues. With regular React Native native dependencies now possible in Expo, a dizzying new array of hard to diagnose bugs can now be triggered, and its unlikely Expo is ever going to go back on their support for arbitrary native dependencies.
Yeah, afaik, in the old template version `npm run export` activated the `expo export` and THAT got deprecated (recently), however at the time (about half a year ago) I thought that the `--local` flag was getting deprecated. Sorry, that was a huge misunderstanding on my end!
The Expo Go app needs to connect to a server for two reasons: the server gives you a signing certificate that is used to sign your project manifest, and it also fetches the list of active and recent projects and Snacks. It is certainly not intended to be invasive.
Expo Go is entirely optional and it is recommended to graduate early on in your development cycle to using a development build of your own app instead. Development builds don't sign project manifests (unless you're intentionally using end-to-end signed updates, an advanced feature). They are like regular development builds of a traditional native app.
Also if you'd like to keep using Expo Go, the signing certificate mentioned earlier has an expiry of 30 days or so IIRC, during which time you don't need to connect to a server. You may still want to provide the "--offline" flag to turn off refreshing the certificate.
Building Expo apps locally is not going to be removed. I am one of the cofounders of Expo.
Being able to build your app on your own hardware is a relatively fundamental feature of any application software framework. The Expo framework is free and open source and we consciously keep it decoupled from Expo Application Services (EAS), which is a suite of hosted services we manage.
Two of the ways to build your app are:
- Entirely locally, without EAS: generate your native Android and iOS projects with "npx expo prebuild:{android,ios}" and build your app with Android Studio/Gradle and Xcode/xcodebuild, respectively.
- With EAS: after getting set up with EAS, installing EAS CLI, and configuring eas.json, run "eas build". There is also a "--local" flag that runs the compilation steps locally and uses your signing credentials managed by EAS.
Many developers use a mix. For instance, they'll build locally when working on a feature for a fast feedback loop. And they'll use EAS to build their release candidates and PR previews to share with their team.
FYI I've made a patchset that pretty much allows me to actually use the EAS --local builds offline and without an EAS account, so it's in fact possible, even though they, for obvious reasons (e.g. https://github.com/expo/eas-cli/issues/1606), don't encourage it.
Would you mind sharing this? I’ve only used expo for experimental non-production apps so far but it works be great to be able to do this if ever needed. Reading this thread makes me a bit more hesitant about using expo.
My full build process is somewhat more complicated to keep my $HOME clean and remove other impurities, but just these patches should be enough to enable offline building.
EAS CLI is designed for EAS, the hosted services. It is intended to use your EAS account, which I suspect is why the PR wasn't accepted.
Expo CLI is for entirely local builds. Run "npx expo prebuild:{android,ios}" to generate your Android Studio and Xcode projects, and build them with the IDEs or their respective CLI tools directly.
Building Expo apps on your own hardware is definitely supported. Specifically, run "npx expo prebuild:{android,ios}" to generate your project's "android" and "ios" directories. Open them up in Android Studio and Xcode (or use their command-line equivalents), respectively, and build.
The managed services (EAS) are optional for Expo apps. The independence between Expo, the free and open source framework, and EAS, the hosted service offering, is something the Expo team consciously works on.
I'm a huge Clojure(script) fan, re-frame is an amazing and super elegant/easy development tool. The awesome this is you can use Clojurescript and Expo together. It was one of the absolutely most pleasant development experiences I've had, especially supporting multiple mobile platforms too. I've also done Android dev and used a Ruby + iOS toolchain before, and done a lot of mobile web. Expo + Clojurescript easily brought the most delightful experience. Interacting with their team was also fantastic, very smart and responsive.
I'm not there yet but totally intended to try putting Clojurescript and Expo together. Too many ideas require apps and Clojure is too great not to take with me yet I wouldn't do apps without Expo.
Exciting! Thanks for sharing!
I'm on re-frame too and that's been a dream.
I just wish I had a better UI lib on the (web) frontend. I went with re-com and it feels a bit half-done, though it's working for all my needs so far, I might just sending PRs if it comes to it.
We're building a universal app in Svelte, which makes Expo completely unusable. We've had to turn to capacitorjs.com instead, which is less mature but gets the job done.
Expo 49[1] was released earlier this month which includes network and VSCode debugging which will make life easier. Even though I registered my Expo 48 mobile app[2] with EAS and did Android + iOS builds, I never received an email about this upgrade...glad this is posted on HN!
I've been using Expo for past 2 years and I enjoyed the experience overall.
But make no mistakes that Expo is a SaaS with the ability to inspect some part of the codebase.
(I stand corrected here) ~Everything important for building and distribution process is moving to EAS, cloud-based service that is not open-source and cannot be self-hosted. So if want to build your app using your own VPS, you are out of luck (at least for Expo managed workflow).~
Again I'm happy with their service and probably would pay for it when the time comes, but the open-source part is not really the big selling point anymore.
You can use the `--local` flag to build on your own computer/CI/VPS. `eas build --local -p ios --profile production` can locally build you an iOS bundle. Don't expect it to work out of the box, though. Your machine should have all the XCode tooling correctly installed and configured. Works for Android as well.
> Your machine should have all the XCode tooling correctly installed and configured. Works for Android as well.
I mean that's the case for the 'regular' React Native workflow as well, and most mobile / crossplatform development. That said, yeah getting RN running is a bit more effort compared to Expo, but it allows for a bit more flexibility.
We decided against using Expo because we had a number of 3rd party dependencies (trackers, analytics, chat, sigh) that had native components; it can work with Expo, but the dependency has to implement support for it, and that was a bit all over the place.
The hosted services offered by the Expo team called EAS has an implementation of an updates server that conforms to that protocol. If EAS went away or you wanted not to use EAS, you could write and operate your own server that conforms to the protocol instead.
The Expo setup that I use never calls into Expo servers at build time. For OTA updates, I've managed to get my self-hosted Expo update server working too, although I'm not using it at the moment, as its incompatible with the React Native New Architecture (it's the last expo package to lack this support - hopefully they'll add it soon).
please do so, I would like to build it totally local and when I realize that outsourcing the build to the EAS cloud saves more time and money I will switch later, that sounds like a nice way to get more people use Expo.
I believe it still uses EAS for certificates by default. You can use "prebuild" to get the ios / android directories. Alternatively start a React Native app and install their modules separately. These options still work well but require a lot more setup.
Expo is the free and open source framework and, separately, Expo Application Services (EAS) is the SaaS. Expo and EAS are designed to be decoupled while also working well together, optionally.
The Expo framework gives you the module system, runtime environment, CLI tools, debugger, a suite of modules, navigation to build universal native apps. They're universal in that there is an Android build, an iOS build, and a web build, and, especially with Expo Router, they work together with universal links. They're native in that the user experience is native to the underlying platform, usually using system UI components and behaviors.
EAS provides hosted services for building your app, submitting it to the stores, and updating it. Many developers will use both EAS and their own hardware. It is convenient and fast to build locally when iterating on a feature. And it is convenient in a different way to use EAS to make preview builds of your app on your PRs that change your app's native code or to make release candidates for production.
Hey. I appreciate that there is a distinction between Expo and EAS.
However, as a user reading the Expo docs, I'm not sure if I can separate them easily without deviating from official docs.
Look at the Expo docs on building and deployment, which are essential steps to getting your app distributed. I don't see any mention of how to achieve it without EAS.
There used to be an expo build but it was deprecated a while ago.
A lot of the docs prioritize ease of getting started and EAS has a free plan generous enough to get you to production and often beyond. The Expo CLI docs have a section on building locally here: https://docs.expo.dev/more/expo-cli/#building
"npx expo prebuild" (covered in that link) is a good command to know. It generates "android" and "ios" directories with your Android Studio and Xcode projects, respectively. These projects can be built entirely locally and there is no dependency on EAS.
As a side note, the old "expo build" command also ran on hosted servers. It was part of the old Expo CLI, which, for historical reasons from six or seven years ago, didn't separate the free & open source Expo framework from the hosted offering. We built EAS years later, with a major new feature being support for builds that have custom native code. Keeping EAS decoupled from Expo has been a conscious effort, and we've also designed EAS to work with any React Native app whether it uses Expo or not.
I guess I'm just saying it would be nice to have an actual "expo build" command that can build the app locally (assuming Android Studio and Xcode are in place), to complete the full Expo framework experience, instead of using expo prebuild and letting the user deal with Android Studio and Xcode manually.
Then again, I can understand why it isn't a priority for the company.
On the surface, yeah, but a bit deeper it allows a more web-style development flow; you as a developer only deal with the Javascript part, nothing about the native part. Expo is a runtime, whereas React Native / Metro is a full mobile app stack.
Likewise, with Expo it's easier to do code push, that is, just release a new JS bundle for over-the-air updates without going through the app store. Again, this is possible in RN as well, but it's a bit more involved.
Finally, Expo allows for easier (internal) demos; anyone with the Expo app installed can scan a QR code during your internal demo to install the app over the air, again without having to go through app stores. This can score you points depending on where you work.
Personally I'm still convinced 'real' native apps are better, but few companies want to invest in development & developers for that. My experience with React Native (not Expo) has been positive so far though, with very little issues between iOS and Android - actually, for me personally it's mainly been figuring out how to install custom fonts (custom fonts and Font Awesome for icons). I hope to not have to touch that again, lol.
It's so weird there is no mention of react native in github README, they only mention react. Did anything changed and expo is not based on react-native?
I use it to create very basic quality-of-life apps coded by ChatGPT. It's great, you can iterate very fast and immediately see the changes on your phone.
However, making your apps depend on a framework has the following dangers:
- the framework might stop being maintained
- the vc-backed framework might need to become monetized beyond your means
At the end of the day, all these frameworks offer are convenience APIs to easily integrate with native things like push notifications or social sign-ins
However, even when these work, they will force you to do things their way, and you won't be able to fully customize your app
Learning how to do these things natively in iOS and Android requires extra effort but pays off in the long term. Using frameworks, the time saved in the beginning of your app development journey will be greatly offset by the extra time required to do things like editing framework output in each build towards the end of your journey
These are a few things I can say as one of the Expo cofounders. We've worked on the Expo framework for over eight years, and did R&D for a year or two before that even before React Native was released. Many other companies and frameworks, even from very large companies, have come and gone in that time and Expo has endured. Paul Graham wrote he found determination "to be the most important quality in startup founders" for what you find that to be worth.
Also from the beginning we believed the Expo framework needs to be free and open source. Introspecting as developers ourselves, we thought people would be a lot more likely to try out and recommend open source frameworks and incrementally build up an ecosystem of modules and StackOverflow answers. Expo gives developers much more agency because it is open source. And it is really hard in my opinion to make a business from licensing developer tools, libraries, and frameworks. There are so many free alternatives.
The goal of the Expo framework is to be the ultimate way to build universal, native application software. Universal apps have builds for Android, iOS, the web, and future platforms. And the user experience is truly native to each respective platform, often by using the native system UI components and not a replica. It does take significant effort to maintain the Expo SDK's set of convenient APIs. It's also just one part of Expo overall.
Separately, the way we are building a business is by offering hosted services for React Native apps, called Expo Application Services (EAS for short). These are optional services for building and updating your apps and using the Expo framework doesn't require EAS. We find developers often use a combination of EAS for some tasks and their own hardware for others.
We work to build developer trust. We are a small company but try to serve developers and our customers well, sometimes better than the companies that have endless trunks of money (we've all seen killedbygoogle.com). So, that's some of how we think about things at Expo.
...and I of course wish you every bit of success. The root cause of many problems is Android and iOS specs changing every 6 months in a not backwards compatible way. It makes maintaining any framework an even bigger headache. I hope you have the determination to keep your level of support high enough to overcome this
Slightly off-topic: how practical is it really to build devices (iOS and Android) and web from the same code base?
My poor understanding is that React Native, and hence Expo, doesn't use the same CSS frameworks as web development. I'm curious how that works from the same code base, or perhaps that's one of the major difficulties.
Also I see Expo as a fancy build framework but it's still fundamentally a RN application. Is this correct?
(My front-end colleagues are on another continent and we don't get any water-cooler time. Sorry for the possibly awful questions.)
I have never attempted to use the web target of Expo, and probably would never try, not the least because so many dependencies assume that the target of a React Native app is either iOS or Android with the web having such different APIs, and the plethora of alternative options for the web.
I’m not using Expo but I do use Capacitor+Quasar to build cross platform apps to great success. I use it for my job and for my side business. Without it I doubt I could run my side business because I just don’t have the time as just 1 person to maintain 3 codebases.
I’ve never used Expo, React Native, or Flutter so can’t speak to those but I’m pretty happy with my setup. Yes I have to put a tiny bit of logic behind checks for if I’m on the web or if I’m in an app but it works surprisingly well overall IMHO.
It has become very practical / doable in the recent year or so. In my experience, if you have lot of frontend web experience, the easiest way to ship a RN app is by using Solito [0]. Also check out Nativewind [1] which allows you to style native apps the same way like you would on web. I was able to ship the first version of our app in about 1.5 weeks with this stack. Also checkout Tamagui [2].
Solito seems to let you share component code, but I assume that it does not share data fetching code? It doesn't do SSR for the native app? And in expo you'd be expected to `fetch` or otherwise get the data yourself (compared to next land where you can just use the next data loading stuff)?
Using Expo and React Native for web is not really practical. But simply having your mobile and web applications both in TypeScript you can share bits and parts of code, most notably the types & data models, application logic code, and assets (from simple image files, through lottie animations, to strings & their translations), but also potentially run some parts of your web application in a webview, ...
The ‘and web’ bit I’ve never found to work well. There’s too many things that work differently on the web
As for the CSS part - yes, React Native uses order for priority, web CSS uses specificity. None of the attempts to get the RN way working on web were amazing
This is the impression I've gotten recently testing their waters. Overall, my take has been to stay away from it unless the app I'm making is simple enough they have templates floating around the web and won't need further tweaking: similar to wordpress, great to have a certain type of app up and running fast but the minute you have to do extensive work on it, you'll wish death on it.
No I don't think so. Next.js adds a truckload of functionality to React, plus handles the server side, etc.
Expo aims to abstract away everything that a web developer wouldn't inherently understand when moving to mobile, i.e. the native stuff. Whether or not it succeeds in that mission, or if it's worth it, is up for debate.
My primary issue with it is the lack of support for in app purchases (last checked in late 2022).
The only easy way to do it is via RevenueCat, as none of the other RN IAP libraries work with Expo.
Expo also has built in support for over-the-air updates, which is great. However, it is a paid product, for $5/m per 1000 users (first 1000 free).
I believe you can run your own server for OTA updates, but it's fairly obvious that this feature will eventually be removed when they need to monetize harder.
Expo these days is pretty extensible and the option to write your own IAP module is a bit easier with Expo Modules, which let you write custom modules with Kotlin and Swift and set up a config plugin to automate changes to your Android Studio and Xcode projects. It definitely would be good for more IAP modules to provide config plugins and automatically integrate with Expo.
The ability to write and run your own update server is a part of Expo Updates and it is not going to be removed. The Expo Updates protocol is an open specification here: https://docs.expo.dev/technical-specs/expo-updates-1/.
Separately, EAS provides an optional, hosted service that implements the server side of the standard Expo Updates protocol and supports both simple and more advanced deployment patterns, for instance: https://docs.expo.dev/eas-update/deployment-patterns/. It also integrates with EAS's build service and appeals to teams looking for managed cloud infrastructure.
I just want to write Svelte and get native apps out the other end. I know we have SvelteNative but that's not great and is a big abstraction. React here is a bit of a bummer i'm not going to lie.
This sounds like the inevitable slow death of RN to me. Web developers simply moving on to new tech that's better/more common on the web while RN languishes as the massive set of open source libraries required are abandoned
Don't confuse HN bleeding edge hipser tech with the real world. The world of react-alternatives is fragmented and lib-incomplete, React still gets more installed than its most popular rivals combined[1].
I have worked across these frameworks and React is the only one where I find the lib ecosystem satisfiyingly large (and still growing most steadily).
I used to maintain Detox for iOS when I was at Wix, from 2017 to 2021. We ended up dropping support for Expo for plenty of reasons, some technical, some "political". The people reporting "issues" (more like asking questions) for their Expo apps, usually had very little technical understanding of any of the increasingly thick environment stack (the Expo layer, RN layer, UI framework layer, OS layer). They were basically web developers who were trying to emulate developing for the browser, with zero interest (and often, capacity) in learning any of the complexities of the aforementioned complex environment.
It was our experience the expo layer added a lot of complexity and many bugs, with very little ability of users to actually fix anything without "ejecting" their project away from that ecosystem. That was on top of the RN layer, which in itself was full of bugs. We would send users to report expo bugs to the expo team, and were first met by "just fix it on your end, you are detox!" type of comments from that silly community, and those that did report the issues, saw no reaction from the expo team, despite detox being one of the most popular testing frameworks in the RN world at the time (no idea about now, but back then, even Facebook was using detox to test RN itself).
At the end of the day, we decided the hassle was not worth the low quality user benefit, so we decided to drop support for Expo. It was one of the best bureaucratic decisions we ever made.
Expo was really lackluster when I last worked with react native around 2018/2019. I hear it has gotten much, much better now but I haven't tried lately
It has. I built an app using Expo several years ago and recently had to update it. Upgrading expo was a pain (as it always is) but the changes and additions in the latest version made so many things easier. And with custom clients, you can do a lot more now than you could before without ejecting.
It's the best way to build React Native apps, with very few exceptions, these days. (I have been building RN apps of all types since it came out in 2015.)
> the increasingly thick environment stack (the Expo layer, RN layer, UI framework layer, OS layer).
This is at the core of my difficulty with cross-platform frameworks for Android and iOS. Dealing with the first-party stack presents enough problems on its own. Adding more layers to that easily compounds the frustration involved in getting anything done.
I learned a while ago that is not worth using an abstraction layer over the official tooling (whatever Apple and Google provides you), even for small apps I was building one for each platform (as one dev).
Tried at the time Xamarin and PhoneGap, and bit later RN, each one has his quirks and things that works in one platform but not in other so in the end you end up building one app for each platform more or less, but with more bugs than the official ones.
I’ve come to the same conclusion. I began to build a very simple app about a month ago and as a Web Dev figured React Native would be the best tool. Having completed about 60% of the app, I’m going to trash the whole thing and restart with Swift/Kotlin. I’ve encountered too many “quirks” that end up burning a huge amount of time for what should be an inconsequential component.
Using Swift UI, or UIKit, has its own quirks. And then you need to shift mental gears with entirely different UI component paradigms.
I find most people making this argument haven't worked full time with one or the other.
If you're a larger company who can afford two teams/groups, or if you are working on something lower level like OpenGL or ML, it makes sense.
Having done both for multiple years, I can't understand when people think it would be faster to build separate apps. It's not even remotely close. You're swapping out doing bug fixes, platform specifics like push notifications, the occasional separate UI implementation, and distribution twice with doing _everything_ twice.
For some bizarre reason I haven't figured out yet, it seems like the "cross platform" choice is always the worst one.
So when people talk about cross-platform on the Mac, for example, it's always some JavaScript abomination, or Java, or Delphi (yes, seriously), or Go.
How about going the other direction and getting Cocoa running somewhere else? GNUstep, Cocotron etc. Gosh, that would actually make sense, can't have that. Literally.
In fact, one company did. Apportable. Google bought them and buried the tech.
On the flip side, Unity is massively successful, and basically every indie game developer who has found any success eventually ends up porting their game to it anyway, precisely because of the cross platform benefits.
The problem isn’t that middlewares are bad. They are great: Unity and Unreal, your browser, Java…
The problem is mobile apps don’t make money. Games and web services do. The OP is talking about low quality users. They’re broke! They’re not incentivized to fix their own problems either! It’s all just a blub for them. So middlewares improve for the audiences where they’re at least viable, and stagnate when they support something that no one should be bothering to do in the first place.
Game dev is a different beast and in most platforms the development/tools are the same or close enough, also when building a game you rely only in low level API (Vulkan, Metal, OpenGL, etc) from the main platform you are targeting. But when you are building an app then you use the hight level API, that means you don't need to deal with font rendering, etc. You could obviously build an app with Unity, but it will not feel native, also IIRC Unity is awful when you need to input text in your game (in iOS at least, not sure how's Android side), it appears a input element above your keyboard while when using the native UI the UX is different.
I've realized that I don't want an abstraction layer. I want a guardrail layer.
Previously, much of my draw to things like Expo has been the reduction in mental load for handling multiple different platforms. In theory, they're built by people who know the different "gotchas" and can help me avoid them.
In practice, something always requires you to dive into the underlying layers. At which point, you're just fighting with bug-filled abstractions.
As a solo dev simple apps are probably the only thing you can maintain two separate versions of? Complex LOB apps at businesses as a solo dev I could never imagine not using a cross platform toolkit of somekind. RN w/ expo is the best I have found out of all the cross platform kits by far.
If you have react experience I really suggest giving modern RN & expo a try.
Modern Expo is very different and in 2023, Expo has full support for custom native code and isn't a layer, so to speak. Ejecting is gone. React Native has also become much thinner in several ways. For instance, developers write Kotlin and Swift with the Expo Modules API and uses JSI (RN's "JavaScript Interface") to directly bind the native methods to Hermes JS methods.
Relatedly, the developer demographic has grown and a lot more developers are adding Kotlin and Swift to their skill sets. They write JS and React most of the time while also writing custom native code when they need to. Most of the best Expo apps include custom native code.
Test frameworks have also grown a lot. I suspect the issues with Detox were often from developers looking to use it with the Expo Go starter app that doesn't support custom native code. These days I hear a lot of positive things about Maestro as well and there was a nice talk on it at App.js Conf earlier this year: https://www.youtube.com/watch?v=uoCzBdFCoqc
I'm glad to hear the tech and, more importantly, the community have improved.
By "layer", I mean custom controls and animation toolkits that get bundled in an Expo-enabled project. Those are in addition to the RN-provided ones. It all adds to complexity.
Expo Modules Core is the only module that is bundled in. It is a small runtime library that defines the Expo Modules API used by other modules, and adds about 150 KB to a production build of an app downloaded from the stores. A hello world iOS app made with Expo ended up being smaller than the same hello world app that used RN without Expo due to the Xcode settings.
There are also no custom UI controls or animation libraries bundled with Expo. The Expo Go starter app includes a preset SDK, and when developers create a build for the app stores or a development build of their own app, only the libraries they use are included.
IMO it would be a meaningful improvement for the react-native package to provide the minimal runtime needed, namely JSI, Hermes, Turbo Modules, Yoga, Fabric, and perhaps a few primitive view components like View, ScrollView, and Text. The package provides more than a library needs. Animations and gestures today are better served in my experience by modules outside of the react-native package, like Reanimated and Gesture Handler that use truly native gestures. React Navigation uses the system navigator UI and Expo Router adds file-based routing and universal links. Expo Image adds support for modern image formats like AVIF and WebP and uses mature, performant image libraries like Glide and SDWebImage. So there is definitely still work to be done that can improve quality and reduce complexity in RN.
171 comments
[ 3.2 ms ] story [ 223 ms ] threadI'm considering RN right now. Wondering whether to start from scratch or not. People refer to issues "ejecting" from Expo but those issues are vague and go back years.
Any concerns or experiences on your end that make it a good or bad option?
But still, upgrading SDK versions to stay on top of security/new features can be a burden with how many breaking changes there are.
I use it for the Rust (video game) companion app, using the stock libraries bundled within Expo so development is a breeze.
https://rust.facepunch.com/companion/
That is great because those project folders are usually quite fragile and can easily break over time.
Before "prebuild" was introduced, you had to stick to expo-included native modules to get that advantage, and if you didn't, you had to "eject", which was hardly better than not using expo at all.
With "prebuild" you can use any native module and still have a git repo free of those fragile iOS and Android folders. It is more work setting up those modules, but it's worth it IMO.
I was afraid because of the Angular roots but the docs (and typescript support) are top notch for Angular/React/Vue.
I could basically transfer all my Vue knowledge (and code).
(Disclaimer: I use Expo at work for cross-platform app including web but never wrote my own plugins)
[1]: https://docs.expo.dev/config-plugins/plugins-and-mods/
With the "prebuild" workflow you can regenerate your iOS and Android projects anytime you need. And set up scripts for adding external libraries in the process.
It is more work to set up over just altering the native projects, but the result is rather nice.
I've never felt 100% confident that react native project folders wouldn't break for arbitrary reasons. Being able to so easily start over is very useful.
Maybe that's better now?
This is in contrast to an IPA or AAB file which can be deployed to a device or distributed to an App Store.
Sounds like I s gotten a lot better and found an actual usecase. I'll have to check them out again.
- Generally a poorer developer experience (bugs, bad documentation).
- Couldn't use some popular/common react native packages. It needed to be compatible with Expo, and there was an expo specific version to use the camera for example. These would have different (and more) bugs. Trying to use any unsupported packages meant ejecting, a hell that might be similar to ejecting from create react app or using craco, perhaps.
- Wasn't really adding much apart from being "all-in-one", but unfortunately each piece was sub par to the original react native.
- Unfortunately the react native docs were defaulting to suggest using Expo. They still do that now: https://reactnative.dev/docs/environment-setup. And yet developers often eject from Expo, so you'd rewrite the scaffolding of your app without expo instead of ejecting. IMHO that's quite sad to see the React Native docs still suggests Expo.
Side note: I've been using Flutter for a few years now, much better developer experience. Doesn't have code push yet, but https://shorebird.dev/ is working on it. (I am not affiliated with them).
eas build --profile develop --platform ios --local
... now looking more into it, I probably mistook `npm run export` / `expo build` with `eas build --local`. Is this correct?
Perhaps the issue you're thinking about was what I linked to in my other comment?
By my own thinking, I believe it's quite unlikely that Expo will ever manage to actually totally remove support for local builds, even though they probably will never encourage it; as otherwise, its really quite impossible to debug native builds, and indeed local builds are Expo's recommendation for debugging such issues. With regular React Native native dependencies now possible in Expo, a dizzying new array of hard to diagnose bugs can now be triggered, and its unlikely Expo is ever going to go back on their support for arbitrary native dependencies.
Turns out the client needs an --offline flag to so so, and I got a bit creeped out to have such a dependency.
Expo Go is entirely optional and it is recommended to graduate early on in your development cycle to using a development build of your own app instead. Development builds don't sign project manifests (unless you're intentionally using end-to-end signed updates, an advanced feature). They are like regular development builds of a traditional native app.
Also if you'd like to keep using Expo Go, the signing certificate mentioned earlier has an expiry of 30 days or so IIRC, during which time you don't need to connect to a server. You may still want to provide the "--offline" flag to turn off refreshing the certificate.
Being able to build your app on your own hardware is a relatively fundamental feature of any application software framework. The Expo framework is free and open source and we consciously keep it decoupled from Expo Application Services (EAS), which is a suite of hosted services we manage.
Two of the ways to build your app are: - Entirely locally, without EAS: generate your native Android and iOS projects with "npx expo prebuild:{android,ios}" and build your app with Android Studio/Gradle and Xcode/xcodebuild, respectively. - With EAS: after getting set up with EAS, installing EAS CLI, and configuring eas.json, run "eas build". There is also a "--local" flag that runs the compilation steps locally and uses your signing credentials managed by EAS.
Many developers use a mix. For instance, they'll build locally when working on a feature for a fast feedback loop. And they'll use EAS to build their release candidates and PR previews to share with their team.
My full build process is somewhat more complicated to keep my $HOME clean and remove other impurities, but just these patches should be enough to enable offline building.
Expo CLI is for entirely local builds. Run "npx expo prebuild:{android,ios}" to generate your Android Studio and Xcode projects, and build them with the IDEs or their respective CLI tools directly.
The managed services (EAS) are optional for Expo apps. The independence between Expo, the free and open source framework, and EAS, the hosted service offering, is something the Expo team consciously works on.
I'm not there yet but totally intended to try putting Clojurescript and Expo together. Too many ideas require apps and Clojure is too great not to take with me yet I wouldn't do apps without Expo.
Exciting! Thanks for sharing!
I'm on re-frame too and that's been a dream.
I just wish I had a better UI lib on the (web) frontend. I went with re-com and it feels a bit half-done, though it's working for all my needs so far, I might just sending PRs if it comes to it.
I wrote and released an iOS and Android app a few years ago and used Expo for ease of cross platform and the hosted build system.
I don't use all the fancy OTA updates and what not, but I can definitely recommend Expo as both a beginner to RN and beginner to iOS+Android app dev.
[1] https://blog.expo.dev/expo-sdk-49-c6d398cdf740
[2] https://github.com/hbcondo/revenut-web
But make no mistakes that Expo is a SaaS with the ability to inspect some part of the codebase.
(I stand corrected here) ~Everything important for building and distribution process is moving to EAS, cloud-based service that is not open-source and cannot be self-hosted. So if want to build your app using your own VPS, you are out of luck (at least for Expo managed workflow).~
Again I'm happy with their service and probably would pay for it when the time comes, but the open-source part is not really the big selling point anymore.
I mean that's the case for the 'regular' React Native workflow as well, and most mobile / crossplatform development. That said, yeah getting RN running is a bit more effort compared to Expo, but it allows for a bit more flexibility.
We decided against using Expo because we had a number of 3rd party dependencies (trackers, analytics, chat, sigh) that had native components; it can work with Expo, but the dependency has to implement support for it, and that was a bit all over the place.
Is the build job also open source somehow?
The hosted services offered by the Expo team called EAS has an implementation of an updates server that conforms to that protocol. If EAS went away or you wanted not to use EAS, you could write and operate your own server that conforms to the protocol instead.
The Expo framework gives you the module system, runtime environment, CLI tools, debugger, a suite of modules, navigation to build universal native apps. They're universal in that there is an Android build, an iOS build, and a web build, and, especially with Expo Router, they work together with universal links. They're native in that the user experience is native to the underlying platform, usually using system UI components and behaviors.
EAS provides hosted services for building your app, submitting it to the stores, and updating it. Many developers will use both EAS and their own hardware. It is convenient and fast to build locally when iterating on a feature. And it is convenient in a different way to use EAS to make preview builds of your app on your PRs that change your app's native code or to make release candidates for production.
However, as a user reading the Expo docs, I'm not sure if I can separate them easily without deviating from official docs.
Look at the Expo docs on building and deployment, which are essential steps to getting your app distributed. I don't see any mention of how to achieve it without EAS.
There used to be an expo build but it was deprecated a while ago.
https://docs.expo.dev/develop/development-builds/installatio...
https://docs.expo.dev/deploy/build-project/
"npx expo prebuild" (covered in that link) is a good command to know. It generates "android" and "ios" directories with your Android Studio and Xcode projects, respectively. These projects can be built entirely locally and there is no dependency on EAS.
As a side note, the old "expo build" command also ran on hosted servers. It was part of the old Expo CLI, which, for historical reasons from six or seven years ago, didn't separate the free & open source Expo framework from the hosted offering. We built EAS years later, with a major new feature being support for builds that have custom native code. Keeping EAS decoupled from Expo has been a conscious effort, and we've also designed EAS to work with any React Native app whether it uses Expo or not.
Then again, I can understand why it isn't a priority for the company.
Likewise, with Expo it's easier to do code push, that is, just release a new JS bundle for over-the-air updates without going through the app store. Again, this is possible in RN as well, but it's a bit more involved.
Finally, Expo allows for easier (internal) demos; anyone with the Expo app installed can scan a QR code during your internal demo to install the app over the air, again without having to go through app stores. This can score you points depending on where you work.
Personally I'm still convinced 'real' native apps are better, but few companies want to invest in development & developers for that. My experience with React Native (not Expo) has been positive so far though, with very little issues between iOS and Android - actually, for me personally it's mainly been figuring out how to install custom fonts (custom fonts and Font Awesome for icons). I hope to not have to touch that again, lol.
However, making your apps depend on a framework has the following dangers:
- the framework might stop being maintained
- the vc-backed framework might need to become monetized beyond your means
At the end of the day, all these frameworks offer are convenience APIs to easily integrate with native things like push notifications or social sign-ins
However, even when these work, they will force you to do things their way, and you won't be able to fully customize your app
Learning how to do these things natively in iOS and Android requires extra effort but pays off in the long term. Using frameworks, the time saved in the beginning of your app development journey will be greatly offset by the extra time required to do things like editing framework output in each build towards the end of your journey
Also from the beginning we believed the Expo framework needs to be free and open source. Introspecting as developers ourselves, we thought people would be a lot more likely to try out and recommend open source frameworks and incrementally build up an ecosystem of modules and StackOverflow answers. Expo gives developers much more agency because it is open source. And it is really hard in my opinion to make a business from licensing developer tools, libraries, and frameworks. There are so many free alternatives.
The goal of the Expo framework is to be the ultimate way to build universal, native application software. Universal apps have builds for Android, iOS, the web, and future platforms. And the user experience is truly native to each respective platform, often by using the native system UI components and not a replica. It does take significant effort to maintain the Expo SDK's set of convenient APIs. It's also just one part of Expo overall.
Separately, the way we are building a business is by offering hosted services for React Native apps, called Expo Application Services (EAS for short). These are optional services for building and updating your apps and using the Expo framework doesn't require EAS. We find developers often use a combination of EAS for some tasks and their own hardware for others.
We work to build developer trust. We are a small company but try to serve developers and our customers well, sometimes better than the companies that have endless trunks of money (we've all seen killedbygoogle.com). So, that's some of how we think about things at Expo.
My poor understanding is that React Native, and hence Expo, doesn't use the same CSS frameworks as web development. I'm curious how that works from the same code base, or perhaps that's one of the major difficulties.
Also I see Expo as a fancy build framework but it's still fundamentally a RN application. Is this correct?
(My front-end colleagues are on another continent and we don't get any water-cooler time. Sorry for the possibly awful questions.)
I’ve never used Expo, React Native, or Flutter so can’t speak to those but I’m pretty happy with my setup. Yes I have to put a tiny bit of logic behind checks for if I’m on the web or if I’m in an app but it works surprisingly well overall IMHO.
[0] - https://solito.dev
[1] - https://www.nativewind.dev
[2] - https://tamagui.dev
As for the CSS part - yes, React Native uses order for priority, web CSS uses specificity. None of the attempts to get the RN way working on web were amazing
1. I can't get a debug build of the app without using their cloud services.
2. Latest version of Android app to preview Expo apps did not work with latest stable Expo version.
3. Random build errors all the time due to some features being deprecated without being mentioned anywhere.
4. Tries to do too much and breaks quite often
This is the impression I've gotten recently testing their waters. Overall, my take has been to stay away from it unless the app I'm making is simple enough they have templates floating around the web and won't need further tweaking: similar to wordpress, great to have a certain type of app up and running fast but the minute you have to do extensive work on it, you'll wish death on it.
Expo aims to abstract away everything that a web developer wouldn't inherently understand when moving to mobile, i.e. the native stuff. Whether or not it succeeds in that mission, or if it's worth it, is up for debate.
My primary issue with it is the lack of support for in app purchases (last checked in late 2022).
The only easy way to do it is via RevenueCat, as none of the other RN IAP libraries work with Expo.
Expo also has built in support for over-the-air updates, which is great. However, it is a paid product, for $5/m per 1000 users (first 1000 free).
I believe you can run your own server for OTA updates, but it's fairly obvious that this feature will eventually be removed when they need to monetize harder.
The ability to write and run your own update server is a part of Expo Updates and it is not going to be removed. The Expo Updates protocol is an open specification here: https://docs.expo.dev/technical-specs/expo-updates-1/.
Separately, EAS provides an optional, hosted service that implements the server side of the standard Expo Updates protocol and supports both simple and more advanced deployment patterns, for instance: https://docs.expo.dev/eas-update/deployment-patterns/. It also integrates with EAS's build service and appeals to teams looking for managed cloud infrastructure.
I have worked across these frameworks and React is the only one where I find the lib ecosystem satisfiyingly large (and still growing most steadily).
[1] https://npmtrends.com/@angular/core-vs-react-vs-solid-js-vs-...
It was our experience the expo layer added a lot of complexity and many bugs, with very little ability of users to actually fix anything without "ejecting" their project away from that ecosystem. That was on top of the RN layer, which in itself was full of bugs. We would send users to report expo bugs to the expo team, and were first met by "just fix it on your end, you are detox!" type of comments from that silly community, and those that did report the issues, saw no reaction from the expo team, despite detox being one of the most popular testing frameworks in the RN world at the time (no idea about now, but back then, even Facebook was using detox to test RN itself).
At the end of the day, we decided the hassle was not worth the low quality user benefit, so we decided to drop support for Expo. It was one of the best bureaucratic decisions we ever made.
This is at the core of my difficulty with cross-platform frameworks for Android and iOS. Dealing with the first-party stack presents enough problems on its own. Adding more layers to that easily compounds the frustration involved in getting anything done.
Tried at the time Xamarin and PhoneGap, and bit later RN, each one has his quirks and things that works in one platform but not in other so in the end you end up building one app for each platform more or less, but with more bugs than the official ones.
It’s more web than RN and depending on what you’re doing might not feel as native, but it’s pretty easy to make a solid app with it.
I find most people making this argument haven't worked full time with one or the other.
If you're a larger company who can afford two teams/groups, or if you are working on something lower level like OpenGL or ML, it makes sense.
Having done both for multiple years, I can't understand when people think it would be faster to build separate apps. It's not even remotely close. You're swapping out doing bug fixes, platform specifics like push notifications, the occasional separate UI implementation, and distribution twice with doing _everything_ twice.
So when people talk about cross-platform on the Mac, for example, it's always some JavaScript abomination, or Java, or Delphi (yes, seriously), or Go.
How about going the other direction and getting Cocoa running somewhere else? GNUstep, Cocotron etc. Gosh, that would actually make sense, can't have that. Literally.
In fact, one company did. Apportable. Google bought them and buried the tech.
Hmm
There’s definitely a huge learning curve and some rough edges, but the speed with which I can write a polished UI in it is staggering.
The problem isn’t that middlewares are bad. They are great: Unity and Unreal, your browser, Java…
The problem is mobile apps don’t make money. Games and web services do. The OP is talking about low quality users. They’re broke! They’re not incentivized to fix their own problems either! It’s all just a blub for them. So middlewares improve for the audiences where they’re at least viable, and stagnate when they support something that no one should be bothering to do in the first place.
Previously, much of my draw to things like Expo has been the reduction in mental load for handling multiple different platforms. In theory, they're built by people who know the different "gotchas" and can help me avoid them.
In practice, something always requires you to dive into the underlying layers. At which point, you're just fighting with bug-filled abstractions.
If you have react experience I really suggest giving modern RN & expo a try.
Relatedly, the developer demographic has grown and a lot more developers are adding Kotlin and Swift to their skill sets. They write JS and React most of the time while also writing custom native code when they need to. Most of the best Expo apps include custom native code.
Test frameworks have also grown a lot. I suspect the issues with Detox were often from developers looking to use it with the Expo Go starter app that doesn't support custom native code. These days I hear a lot of positive things about Maestro as well and there was a nice talk on it at App.js Conf earlier this year: https://www.youtube.com/watch?v=uoCzBdFCoqc
I'm glad to hear the tech and, more importantly, the community have improved.
By "layer", I mean custom controls and animation toolkits that get bundled in an Expo-enabled project. Those are in addition to the RN-provided ones. It all adds to complexity.
There are also no custom UI controls or animation libraries bundled with Expo. The Expo Go starter app includes a preset SDK, and when developers create a build for the app stores or a development build of their own app, only the libraries they use are included.
IMO it would be a meaningful improvement for the react-native package to provide the minimal runtime needed, namely JSI, Hermes, Turbo Modules, Yoga, Fabric, and perhaps a few primitive view components like View, ScrollView, and Text. The package provides more than a library needs. Animations and gestures today are better served in my experience by modules outside of the react-native package, like Reanimated and Gesture Handler that use truly native gestures. React Navigation uses the system navigator UI and Expo Router adds file-based routing and universal links. Expo Image adds support for modern image formats like AVIF and WebP and uses mature, performant image libraries like Glide and SDWebImage. So there is definitely still work to be done that can improve quality and reduce complexity in RN.