The following article is part of The Ultimate Guide to React Native Optimization and explains how you can optimize your React Native app’s performance using different bundlers, like Re.Pack, <rte-code>react-native-esbuild<rte-code>, and <rte-code>rnx-kit<rte-code>.
Why is this important?
In other blog posts based on The Ultimate Guide to React Native Optimization, we touch on the following topics related to improving performance through understanding the React Native implementation details:
- Picking the right external libraries for your app
- Optimizing battery drain with mobile-dedicated libraries
- Animating at 60FPS
- Improving React Native performance with high-order components
Using alternative bundlers to optimize performance
There are a few alternative bundlers that could be used in React Native apps and provide more configuration features. In this article, we’ll take a closer look at Re.Pack, <rte-code>react-native-esbuild<rte-code>, and <rte-code>rnx-kit<rte-code> and consider their benefits and limitations.
Re.Pack is a Webpack-based toolkit to build your React Native application with full support of the Webpack ecosystem of loaders, plugins, and support for various features like symlinks, aliases, code splitting, etc. It is the successor to Haul, which served a similar purpose but balanced a different set of tradeoffs and developer experience. By the way, we’re proud to say that Re.Pack it brought to you by our React Native development company – and we put in every effort to make it as valuable and developer-friendly as possible.
Benefits of using Re-Pack in your React Native project
Another Webpack feature that helps our apps achieve better performance is reducing the amount of code in the final bundle with tree shaking. Tree shaking is a dead code elimination technique done by analyzing the import and export statements in the source code and determining which code is actually used by the application. Webpack will remove unused code from the final bundle, resulting in a smaller and more efficient application. The code that’s eligible for tree shaking needs to be written in ECMAScript modules (import and export statements) and mark itself as side-effect free through <rte-code>package.json<rte-code> <rte-code>sideEffects: false<rte-code> clause.
The very first issue on Metro bundler’s GitHub is about symlink support. It remains open today, as there are various reasons Metro is blocked from introducing this functionality with the desired DX. There are ways to mitigate that particular shortcoming, but they require extra configuration. Webpack, on the other hand, as virtually any other bundler, and doesn’t have this issue. Re.Pack uses the Webpack bundler under the hood, so it provides symlinks functionality out-of-the-box, which could be invaluable from the developer experience point of view of some workflows like monorepos.
On top of that, Webpack 5 introduced support for the concept of Module Federation. It’s a functionality that allows code-splitting and sharing the split code parts (or chunks) between independent applications.
It also helps distributed and independent teams to ship large applications faster. Giving them the freedom to choose any UI framework they like and deploy independently while still sharing the same build infrastructure. Re.Pack 3 supports this functionality out-of-the-box.
Where Metro works out better than Re.Pack
All these configurations and flexibility affect the build process. The build speed is a little bit longer than the default Metro bundler due to customization options. Also, the Fast Refresh functionality is limited compared to the Metro bundler. The Hot Module Replacement and React Refresh features require the full application to be reloaded with Webpack and Re.Pack, but they are supported by Metro.
If you don’t need the huge customization that the Webpack ecosystem offers or don’t plan to split your app code, then you may as well keep the default Metro bundler.
The next bundler that can help you optimize your React Native app’s performance is react-native-esbuild, which comes with speed, tree shaking, compatibility, and configurability. Let’s take a closer look at this tool.
Why it's worth considering react-native-esbuild for your React Native project
One of the main benefits of react-native-esbuild is fast builds. It uses the ESBuild bundler under the hood, which greatly improves bundling performance even without caching. It also provides some features like tree shaking and is much more configurable compared to the Metro bundler.
ESBuild has its own ecosystem with plugins, custom transformers, and env variables. This loader is enabled by default for <rte-code>.ts<rte-code>, <rte-code>.tsx<rte-code>, <rte-code>.mts<rte-code>, and <rte-code>.cts<rte-code> files, which means ESBuild has built-in support for parsing TypeScript syntax and discarding the type annotations. However, ESBuild does not do any type checking, so you will still need to run type check in parallel with ESBuild to check types. This is not something ESBuild does itself.
The drawbacks of react-native-esbuild
Unfortunately, <rte-code>react-native-esbuild<rte-code> has some tradeoffs, so it is very important to select the right bundler by paying attention to them as well. It doesn’t support Hermes, which could be a crucial point for some projects. And it does not have Fast Refresh or Hot Module Replacement, but this library supports live reload instead.
Last but not least, we’d like to discuss Microsoft’s rnx-kit. It’s an interesting extension to Metro. <rte-code>rnx-kit<rte-code> is a package with a huge variety of scalable React Native development tools. It also has a custom bundler that works on top of the Metro bundler, enhancing it.
The pros of enhancing Metro with rnx-kit
As you already know, Metro does not support symlinks. <rte-code>rnx-kit<rte-code> provides the ability to fully work with symlinks. One more benefit compared to Metro is the tree shaking functionality out-of-the-box.
Also, <rte-code>rnx-kit<rte-code> provides duplicate dependencies and cyclic dependencies detection out-of-the-box. This could be very useful in reducing the size of the bundle, which leads to better performance and prevents cyclic dependencies issues.
The choice of a bundle tool depends on the specific case. It is impossible to select only one bundler for all the apps. If you need customization options provided by the Webpack ecosystem or plan to split your app code, then we would suggest using Re.Pack for its widely customizable configuration, a huge amount of loaders, plugins maintained by the community, and a lot of features like symlinks, aliases, etc. compared to other bundle tools.
If the Webpack ecosystem feels overhead, then it is better to stay with the default Metro bundler or try to use other bundler options like <rte-code>react-native-esbuild<rte-code> and <rte-code>rnx-kit<rte-code>, which also provides some benefits like decreased build time, using esbuild under the hood, symlinks, and typescript support out-of-the-box. But be careful and always pay attention to the tradeoffs that come with a new bundling system.
If you need help with performance, stability, user experience, or other complex issues, contact us! As React Native Core Contributors and active Open Source contributors, we will be happy to help.