Coming to Expo: a new open-source repo, TypeScript, best-in-class APIs, custom native code, more platforms, and much more
Expo developers include a wide variety of people making apps with Expo in different ways. To learn more about the most popular apps made with Expo we talked to developers and looked at production apps and found that most of them are made by professionals as part of a business. People who use Expo for business use it sometimes everyday and rely on it in part for their livelihoods as professional programmers.
Over the past few months we’ve been working on features and structural changes to the Expo platform to better serve skilled professionals and give them the agency to build high-quality apps with pride. Today, we’d like to share with you: how Expo is changing to increase agency for developers, our focus on quality and rigor, improvements to the developer experience, and some of the future direction of the Expo project.
Sections
- Developer Agency: Open-Source-First Development, One License (MIT), Self-hosted JS, Self-built Standalone Apps, and Custom Native Modules
- Craft, Quality, and Rigor: High-quality APIs, Stability, Robust Tests, React Navigation 3, and Beyond Android and iOS
- A Professional Developer Experience: Expo CLI 2, TypeScript, Single-SDK Builds, and Teams
- The Future: SDK 31 and Modern JSC; Background APIs; 64-bit APKs; Paid Services; and Speed, Quality, Universality, Stability, and Flexibility
🛠 Developer Agency
When working on apps, developers look to build the features they envision for the app on a timeline they choose. Achieving these goals is largely up to a developer’s ability and decisions but sometimes a platform or technology can be a bottleneck. In Expo’s case, we see that skilled developers often wish it were easier to write custom native code or contribute back to Expo. We also receive many requests to add more APIs. Some developers also have asked to build their app binaries on dedicated hardware or to host their app JS and assets on their own servers. A common thread across these scenarios is that developers are blocked on Expo in different ways; to address these issues sustainably, we want for skilled developers to have the agency they need to build high-quality apps and for Expo not to be a bottleneck. We have made several ad hoc and systemic changes in this vein and plan to work on several more.
Open-Source-First Development
One of the major structural changes we made was to move development of the Expo client software from a private repo to an open one. In the old model, slices of source code from Expo’s private repo (Universe) were automatically synced to several public repos, similar to how the React Native repo is set up. While this model let us open source the Expo client and let contributors send pull requests, we found it created disparity between the way the Expo team developed in the private repo and the way community contributors developed in the open repo. We were less likely to notice and fix issues with the open repo and extra surface area from the disparate workflows added to our maintenance cost. Our new model structurally minimizes this disparity to encourage more community contributions and easily maintain the open-source workflow.
The main Expo repo is now the source of truth of the Expo client and where both the Expo team and community contributors develop. Making the open GitHub repo the source of truth is a systemically healthier model for Expo compared to syncing from a private repo. As part of this evolution, we made the open Expo repo a monorepo—it now contains the Android and iOS runtimes, many Universal Modules, the JS SDK, test suites, the Expo Babel preset, and more — so the implementation of one idea can be in one coherent commit and PR, even if it spans across multiple platforms and programming languages.
We hope the new model encourages developers to contribute to Expo and feel more able even to fork it if they need to.
Press enter or click to view image in full size
One License (MIT)
Along with moving the Expo client’s source of truth to the open repo, we changed Expo’s various licenses (previously a mix of BSD and MIT) to the MIT License across the board. We chose the MIT License for two reasons: it is popular and relatively well-understood, and both React and React Native now use it. In practice, the BSD and MIT licenses are widely accepted and we expect this change not to significantly affect any developers, but hopefully it is simpler to think about just one license for Expo’s code now.
Self-hosted JS
The JS and some assets for Expo apps are typically hosted by Expo and served through our globally distributed CDN. This is convenient, high-performance, and works well for most developers, but some developers have asked for a way to host their code and assets themselves for various reasons.
We added a new command to the Expo CLI called expo export, which exports a set of files you can host from any static web server your app can access. The Expo docs have a guide to Hosting an App on Your Servers and if you find it interesting to learn about the technical choices behind our work, watch Quin Jung’s talk from React Native EU 2018 (22 minutes).
Self-built Standalone Apps
When Expo developers (using the Expo client) are ready to submit their apps to the App Store and Google Play, they use Expo’s standalone app builders to create IPA and APK files with binaries. Like Expo’s hosting service, the standalone-app builders are convenient and work well for most developers. However, the builder service is shared and sometimes there are wait times or builders go down. We are working on addressing these issues but also wish to give developers more agency when it comes to building standalone apps. To this end, we’ve been working to make the Expo standalone-app builder open source.
The builder, called Turtle CLI (standalone Expo apps are also known as “shell apps” 🐢), is a program you can run on your own computer, server, or CI service. It is written in TypeScript and requires Node.js. For Android builds you’ll also need the JDK and for iOS builds you’ll need Xcode. See the guide on Building Standalone Apps on Your CI Service for how to get and run Turtle CLI.
Custom Native Modules
A very popular request for Expo is the ability to write custom native modules. ExpoKit is a native Android and iOS library that lets you still write your app in JS and use Expo APIs while having an Android Studio or Xcode project in which you can write native code. ExpoKit has been a part of Expo for awhile through “detaching” an Expo project but many developers are unaware of it or find it hard to use. From a technical perspective, the pre-built Expo client app from the App Store cannot support custom native modules and ExpoKit or a similar approach is necessary. To address these requests and constraints, we are looking to make ExpoKit a first-class workflow in the future.
With ExpoKit as a first-class workflow, writing custom native modules and native code in general, debugging native and JS code, building binaries on your own CI services, and customizing other parts of your app will be much more streamlined. In addition, we look to make it easier to build custom Expo client apps with custom native modules so you can work on your JS the same way you would with the Expo client app from the App Store while still having your custom native modules.
We believe ExpoKit is the most sustainable solution to broad classes of items in the very long list of requested APIs. The best way for the Expo team to help professionals is to invest in ExpoKit, unblocking developers from writing custom native modules. Additionally, maintaining APIs is expensive for the Expo team, especially as costs accrue in perpetuity. For Expo to succeed, we are looking to invest more in ExpoKit than in new native modules and to create agency and a path forward for skilled professionals to write the native modules they need.
💯 Craft, Quality, and Rigor
When folding origami, the crispness and precision of the early creases shape the final piece. Software is similar and Expo’s level of quality affects the user experience of the final app. Insofar as software is a craft, we are looking to invest more in tasteful, cohesive APIs and increase our attention to detail through our code to our docs.
“For you to sleep well at night, the aesthetic, the quality, has to be carried all the way through.” — Steve Jobs
Insofar as software is engineering, we are raising the level of rigor applied to Expo, starting with the SDK.
High-quality APIs
We are prioritizing quality over quantity and revisiting the existing APIs in the Expo SDK. Our API design values include simplicity and consistency while exposing platform-specific capabilities when needed. In the general case, we want the Expo SDK to behave consistently across platforms and feel consistent across APIs. We are starting with APIs written by the Expo team but the Expo SDK as a whole includes React Native and externally maintained APIs and we need Expo to be consistent and high-quality across the board.
Press enter or click to view image in full size
Another important aspect of Expo’s API design is comprehensive consideration of edge cases, concurrency guarantees and race conditions, side effects, and other aspects of an API not communicated in a function signature. For example, we are adding explicit error codes to thrown errors that are consistent across platforms, and working to ensure the errors are thrown under the same conditions across platforms.
Stability
A long-term goal of Expo is to achieve API stability in the vein of the web and continuously release updates with few breaking changes. In practice, because the underlying platforms like Android and iOS annually introduce breaking changes, Expo will have some breaking changes too, but we’d like for those changes to be infrequent and for there to be smooth migration paths.
To start, as part of revisiting the existing Expo APIs, we are designing our APIs with some future-resilience in mind as the underlying platforms change and as we add new platforms to Expo. Eventually we will need other parts of Expo such as the rendering engine and JS–native bridge to be stable, too, but to start we are focusing on APIs authored by Expo.
Robust Tests
Getting code working is often much easier than keeping it working over time, and writing code is often easier and cheaper than maintaining code. To drive down Expo’s maintenance and to preserve a high quality bar, we are adding more tests to the Expo SDK. We have three types of tests:
- Jest tests: the unit under test is pure JS and we test the integration between JS functions or statements within a single function. These tests mock native modules and I/O and need to run quickly to provide continuous feedback during development.
- End-to-end tests: the unit under test is the entire implementation of an API — including its JS, the native module, the Expo runtime, and the underlying platform — and we test the integration of all of those parts.
- Native tests: the unit under test is pure native code and we test the integration between our native functions and sometimes the underlying platform. We also sometimes mock the underlying platform depending on our intent behind what to include in the unit under test.
We are also writing the SDK in TypeScript — another kind of test — to improve the robustness of both the SDK and apps that use it.
React Navigation 3
Nearly all apps have more than one screen and use a navigation library for one of the more complex components in the app. We invested heavily in React Navigation to get it to the 1.0 release and since then have continued to lead the project to 3.0. Some of the reasons we’ve invested so much in React Navigation are because it benefits almost all apps, React Navigation significantly benefits from full-stack optimizations (ex: using native navigation primitives) that push Expo forward, it provides a consistent API across platforms, and runs on platforms beyond Android and iOS like the web.
Get James Ide’s stories in your inbox
Join Medium for free to get updates from this writer.
In React Navigation 3, the major features are:
- Better graphics performance in the stack navigator: we optimized the card shadow and opacity during transitions and made it possible to toggle both the shadow and opacity on and off. As a bonus, the shadow now properly animates like it does with UINavigationController.
- Integrated
react-native-screens: screens build on top of UIViewControllers on iOS and Fragments on Android. Each screen is represented by the same primitives as they would be in a typical native app, rather than a plain view. This will reduce memory usage in most apps, adds support for Reachability on iOS, and paves the way for better integration with other native components because screens now have the same native lifecycle. - Native gesture handlers: the stack and drawer navigators now use
react-native-gesture-handlerwith the native driver for smoother gestures and better interactions and control over interactions with other gestures. - Other improvements: new “back” and “slide” types for the drawer navigator, list and scroll views that automatically scroll to the top when tapping an active tab, support for default parameters in route configurations, and many bug fixes.
- The next major release will likely migrate to
react-native-reanimatedfrom React Native’s Animated API. This will complete the puzzle of letting us run all transitions entirely on the main thread — from the start of a gesture to when you fling to dismiss a screen or modal.
Beyond Android and iOS
Android and iOS are two of the most popular platforms in the world and mobile usage continues to rise. However, in addition to native Android and iOS, the web browser on mobile devices is also very popular. Since Expo apps are primarily written in JavaScript and React anyway, we believe that as our APIs and developer tools mature, targeting additional platforms such as the web is viable for Expo. In particular, React Native for Web has shown it’s possible to create websites that load quickly, behave as normal websites, and have as much complexity as Twitter’s mobile site.
As we revisit Expo’s existing APIs, one of our API design criteria is how well the API could extend to many platforms and, in particular, how well it maps to the corresponding web API if one exists. Keeping the web in mind as we revisit component APIs in particular is a key step along the path to defining universal React components (ex: a standard <Image>) that all React libraries — whether for web or for native — can use, instead of web libraries using <img> and native libraries using <Image>.
Web support is a long-term future initiative we are considering when revisiting Expo’s APIs, and we will post the first updates on the Expo blog when the time comes. For now, we will continue to focus on Android and iOS and making our existing APIs best-in-class.
🥇 A Professional Developer Experience
The developer experience is another facet of Expo we have been working on to better support professionals. As with the Expo SDK, we are also raising the quality bar of our developer tools by increasing test coverage and attention to detail in the software the Expo team writes and by making reliable, trusted choices for the software Expo depends on.
Expo CLI 2
About a month ago we released Expo CLI 2, the replacement for XDE, the exp CLI, and create-react-native-app. Expo CLI includes a terminal CLI and a browser-based GUI, combining the best of both worlds for a superior developer experience while helping the Expo team sustainably maintain one tool and repo. See Ville Immonen’s announcement of Expo CLI 2 for more about the features of Expo CLI.
One significant change not covered in the announcement is that we moved development of Expo CLI from Expo’s private repo to an open one. Like the Expo client repo, the new Expo CLI repo is open-source-first and aligns the Expo team’s workflow with the community contributors’ workflow. The repo contains all of the parts of Expo CLI so that it is easier to write one PR that spans various parts. We hope this will make it much easier to contribute to Expo CLI.
Press enter or click to view image in full size
TypeScript
Whenever someone from the Expo team talks to developers at JS conferences and asks about the type system they use, if any, the resounding answer is TypeScript. We explored TypeScript by using it for an internal project (our iOS push notification server) and found the type system and inference, tools like VS Code, community knowledge on GitHub and StackOverflow, and the general ecosystem all to be healthy. Additionally, Babel 7 added support for parsing and compiling TypeScript, paving the way for smoother TypeScript integration into the JS preprocessor. After getting feedback on an RFC issue to add first-class support for TypeScript to the Expo SDK, we have decided to move from Flow to TypeScript.
The migration to TypeScript is incremental and underway. A large portion of the Expo SDK is already written in TypeScript but we have several more Universal Modules to migrate. After migrating the SDK, we will be able to explore making it easier to write apps in TypeScript and check types across application code and the Expo SDK. We hope this work will further help Expo developers who are already using TypeScript in other projects or have been interested in trying it.
Single-SDK Builds
Previously, standalone-app binaries made with the Expo standalone-app builder service included the native code for the six most recent SDK versions. This allowed developers to change SDK versions when publishing JS updates but we found this rarely to be used in practice. We changed the builders and the Expo client to support single-SDK builds and standalone apps now contain only the SDK version they use when built.
Single-SDK builds are faster, produce smaller binaries, and are isolated from other SDKs. On Android, build times dropped from about 12.5 minutes to 11 minutes (1.1x reduction) and the size of a basic APK dropped from 27MB to 19MB (1.4x reduction). On iOS, build times are the same due to how the builders work and the size of a basic IPA dropped by several hundred megabytes (IPAs contain bitcode and are much larger than the final apps downloaded from the App Store). Additionally, isolating SDK versions means changes to one SDK version are unlikely to affect standalone apps built with other SDK versions. Overall, we hope faster build times and increased isolation will improve the Expo developer experience.
Teams
Many Expo developers building business apps work with teammates on the same app. Expo projects are associated with a single account, so multiple teammates need to share the same account in order to publish JS updates to their app and initiate builds with the Expo standalone-app build service. To facilitate working with teammates, we are working on adding support for team accounts later this year and will have more details and guides to share when the time comes.
📈 The Future
SDK 31, Babel 7, and Modern JSC
The next release of the Expo SDK will be SDK 31. We are upgrading to React Native 0.57.1 and React 16.5.0. Two other notable upgrades are Babel 7 and a much more modern version of JavaScriptCore (JSC) on Android.
Babel 7 brings many changes to its package names, configuration files, and plugin ecosystem and supports TypeScript. SDK 31 will include a new Babel preset for Expo apps that has been upgraded to work with Babel 7.
We also plan to upgrade JSC, the JS virtual machine, on Android. Expo currently uses a version of JSC from four years ago. The new version of JSC is close to iOS 11’s JSC and includes support for nearly all ES2015, ES2016, and ES2017 features such as Symbols, for-of loops, and generators without requiring Babel compilation or runtime libraries. We are optimistic the upgrade will go smoothly but as it is a significant upgrade to one of the most complex parts of Expo, the upgrade may be delayed if issues arise. Hopefully Expo will include modern JSC soon and enable more modern JS features, faster Babel compilations, and smaller JS bundles.
Background APIs
We have also been working on support for a small number of background APIs, including geolocation. A large part of this project is adding support for background work to Universal Modules. We expect to introduce our first background API later this year.
64-bit APKs
In August 2019, Google will require 64-bit support for all apps submitted to Google Play. We aim to be ready before this deadline and have taken the beginning steps towards this goal by dropping support for Android versions that don’t support 64-bit builds and upgrading our Android toolchain.
Paid Services
Expo is a free and open-source platform, which we believe is critical for Expo to succeed. When we talk to developers using Expo or at conferences, though, a common sentiment from professionals working on business apps is they’d feel more confident using Expo if we offered paid plans. We are evaluating ways to offer plans for paid services while keeping Expo’s software free.
As explained earlier, we’ve moved development of the Expo client to the open GitHub repo, and we hope this reaffirms that Expo’s software will stay free and open source. Additionally, supporting self-hosted JS and open sourcing the Turtle CLI builder means developers can serve JS and build app binaries independently from Expo’s services. We believe this is integral to the success of the Expo platform and an important part of why we’re working on Expo; Expo’s software will stay free and open source and developers won’t need to pay money to make apps with Expo.
For businesses interested in a paid plan, we are looking to provide paid services with that are convenient, high-performance, and supported by the Expo team. We are just starting to think about payment models for businesses and will share more when we are closer to offering paid plans.
Speed, Quality, Universality, Stability, and Flexibility
Lastly, we’d like to share some of our product values to give a sense of our work in the future. These are five of them:
- Speed: we want to improve performance in several ways, including how long it takes to launch an app, how quickly you can see your changes during development, and how fast it is to create a new project.
- Quality: we’re working so for apps made with Expo to have high-quality user experiences with native views and responsive gestures and to offer coherent, thoughtful, and reliable APIs to developers.
- Universality: Expo and JavaScript are suited to more than native Android and iOS apps and expanding to support other platforms like the web is along the natural path for Expo.
- Stability: with stable APIs and tools, we can reduce the cognitive tax for all Expo developers and make it easier to keep using Expo for the long term, and also improve the stability of apps in production.
- Flexibility: we aim to give skilled professionals more agency to build the features they need by improving support for custom native modules with ExpoKit, making it easier to contribute to the open Expo repo, and other ways we can remove the Expo team from being a bottleneck.
These are long-term investments and we’ll continue to work hard in order to serve developers and help you build great apps. For professionals using Expo for your businesses, we appreciate your being part of the Expo developer community and helping make Expo a success. And for those working on more playful projects, we hope to share with you some more exciting news soon! 🏰
Thank you for reading, especially this far. 💮
Press enter or click to view image in full size