Video details

React Native EU 2021: Paweł Trysła - Code Splitting in React Native

React Native
10.12.2021
English

This talk was presented during the React Native EU 2021 - the biggest community conference in the world focused exclusively on React Native.
Abstract: While developing mobile applications we usually have a mental model of a single runnable piece of software that includes all features and there’s a good reason for that - it’s difficult to split functionality in native mobile applications. However, with React Native most of our logic lives as a JavaScript, which can be splitted. The web development community has been doing that for years. So what if we could split our React Native code using the power of Webpack?
Paweł Trysła aka. Zamotany is a software engineer at Callstack and the lead engineer at Re.Pack. Paweł calls himself “the tooling guy” with extensive knowledge of Webpack and Babel. He is also a huge fan of Electron, functional programming and RxJS.
Twitter: https://twitter.com/_zamotany
Github: https://github.com/zamotany

Transcript

This conference is brought to you by Code Stack, React and React Native Development Experts Hello, everyone. I'm Pablo Threshold, also known as Zamutan on the Internet, and I'm a software developer at Cod. Today. I'm going to talk about code splitting in React Native, so let's start by answering the question what code splitting actually is? Code splitting is a technique to split the code of your product into multiple bundles. Those bundles can be loaded on demand or in parallel. Instead of shipping the whole applications code to the user, you only deliver the bare minimum of the code and load the list later, once needed. Now, before we move forward, let's establish what a bundle is. In a nutshell, a bundle is a single file container for your code. It includes compiled source code, all necessary, dependencies, and in some cases, static files. You might be wondering why we need a bundle for React Native applications. Well, your project, in order to be executable by React Native needs to be processed and converted to a format with JavaScript virtual machine inside React Native. Understand, we call this format a bundle and usually in React Native applications. Your project is contained inside single bundle, but doesn't have to be that way. Let's talk about code splitting with code splitting. The project's. Compiled source code dependencies and static assets are part of multiple files. Instead of a single one. The entry point to the application is included in the main bundle, sometimes referred to as an entry chunk, and it includes all necessary code for the application to work and minimal code to present something to the user. All additional features and logic are contained in the additional files called chunks. Those chunks can contain features needed later in specific situations or for specific group of users. There are two main usages of code splitting in context of React Native dynamic content and feature delivery, which allows to provide certain features on demand or for a specific user or group of users. Secondly, there's an optimization use case because code splitting allows to load the code later on demand, it can be used to defer code Loading until it's needed. This can improve time to render and time to interactive. Since React Native has to load and execute less code initially at the startup, let's look at some of the examples of code splitting in mobile applications. First, examples are so called super apps or mini app stores. Those applications consist of multiple, small, dedicated services, sometimes referred to as mini apps. It's a closed ecosystem where service or a miniapp is tightly integrated to provide a great and efficient experience for the user. Because a super app or a mini app store can contain tens of hundreds of mini apps, not every user will use all of them. Based on that. It would make sense to download and execute the code only for the ones that the user intends to actually use, and then the house application would initially only ship the core APIs and functionalities to the user. As for the example of super apps that exist on the market today, we have a couple of them, but the ones worth mentioning are Alipay and WeChat WeChat for its sheer size of 1 million miniaps and Alipay for a tightly integrated ecosystem of services that work together to provide great experience for the customer. So on one hand, we have super apps and mini app stores, but Cosplayting has use cases in other group of applications as well. I call the modular applications. It's an umbrella term of applications that could extract part of the functionality into modules loaded OnDemand or based on random factors like user role or group role subscription plan or preferences. Modular application description is a special fitting for applications heavily based on reserve roles. For example, elearning applications or school related applications where we have vastly different functionalities for student and for teacher. So based on the user role, the application could only load student functionalities or teacher functionalities. This would improve initial download size and startup performance. Another example would be companion applications for hardware and physical devices. We could put here most of the automotive applications where functionalities could be splited into on demand loaded chunks based on the vehicle parameters. Now that we know what types of applications can benefit from code splitting, let's see how code splitting can be implemented inside mobile applications. Let's start with Android natively on Android, we can use feature called Play Feature Delivery. It allows to split native code into multiple bundles. It is even possible to embed React native inside such bundle in context of React native Play feature delivery can be an option for browser applications, but Play feature delivery has some drawbacks. The biggest one is that Play feature delivery is a native functionality, so it will be difficult to create architecture where JavaScript code uses the same JavaScript virtual machine. It would be much easier to create application with multiple React native instances, each one in its own Play feature Deliver bundle. This means that native coding skills and knowledge is required to pull off such architecture, and it will be mainly used for form browsing applications for green feed applications. Though the challenge to share single JavaScript virtual machine will be a major blocker on iOS, there is OnDemand resources functionality that could be used to split some of the content like data, images, shaders particles, and similar. However, native code cannot be an on demand resource, which is a real blocker since we are looking for splitting logic by splitting the code. Even if we still want to split the native code without using on demand resources, it would be extremely challenging due to the static nature of binary code, and more importantly, there is a high chance that it would be rejected by App Store review process as it would violate the App Store guidelines. Okay, so it will be problematic to achieve code and contribute on both platforms. Are there other options? Yes, they are, and Web views are one of them. They are extremely easy to work with and introducing them wouldn't be a difficult task. They can be used both in Native applications and in React Native. However, they provide suboptimal experience for the user. Web users are likely to have performance issues, and they don't provide the native look and feel that you strive for. Luckily, there's React Native with Reignative using default JavaScript bundler called Metro, it is possible to create a closed platform solution for splitting the code without sacrificing user experience and the APIs to make it happen are already part of the React Native. You could use execute application script method on iOS and load script from file or loads script from assets or Android, but you will likely run into troubles with dependencies data application and in general code sharing between chunks. The Metro bundler is not well suited for this, or at least it's not well documented. Splitting the code using Metro would also mean that for each additional chunk, you would need to spawn a new development server, and fast refresh would only work for the main bundle out of the box. It might be possible to overcome all of these problems, but it would require a lot of effort, knowledge, and skill. So what else can we use them? If you're coming from Web or have background from Web development, you might be wondering, why couldn't we use the same solution for code splitting in mobile applications as on the Web? That's the same question I've been asking myself and for React Native, I think we could by using Web Pack. It's a commonly used bundler on the Web. It has huge ecosystem, lots of configurations, options, and most importantly, for us, well established code splitting functionalities. However, if you tried using Webpack to bundle your React Native application, you would ultimately hit a major blocker. Webpack is not compatible with React Native, at least not by default. In fact, the plugin ecosystem in Webpack is so flexible that we could breach this gap and make Webpack compatible with React Native. And that's exactly what we did. We named this project Repack. Repack is a toolkit that makes Webpack compatible with React Native. It enhances and changes the bundle that Webpack produces so it can be executed by the JavaScript virtual machine inside React Native. It takes into the account that the code in React Native runs in different environments with different APIs needs, different setup code, and so on. Repack itself was created as a successor to another open source project called hall. But compared to hall, it takes different approach. With Repack, you still have access to Webpack configuration, and Repack gives you only the plugins and helpers to allow you to use Webpack in React Native applications. It doesn't hide anything from you. It gives you a fully featured development server, support for REAG, refresh, and compatibility with Flipper. Except for Ram bundles, repack has a feature parity with Metro as of today. So if you want to use Web Pack with React native, the easiest way to do so is with Repack. Now let's evaluate React native with Repack and Webpack as a code splitting option. The first advantage is that the solution is based on Web Pack itself, which has wide variety of configurations options, and we can adjust it well to our needs. Additionally, it has huge ecosystem community, and it's widely used meaning is it's stable and established software together with Repack, it's a class platform solution focused on code splitting, but everything has its drawbacks because it's Web pack, it has a high entry barrier, especially for less experienced developer. It will be challenging to configure Webpack if you don't have previous experience with it, so it can take up some time to get familiar with the biggest point of Web Pack, which is its configurations options, is a double edged sword. It's powerful, but it can be overwhelming. Nevertheless, based on other options, it seems to be the best one, at least for the time being. Competition and alternatives are always a good thing, so let's explore cosplaying with Web Pack and three Pack. Essentially, there are three approaches to code splitting with Webpack and Repack for React native async chunks, dynamic scripts, and model Federation. Let's start with async chunks. The easiest approach. The additional chunks are created from a single codebase as part of a single compilation, also known as Bundling process. New chunks can be created by using dynamic import function, and the first argument for this import function is a path to a module which will become an entry point to a new chunk. Chunks created by this approach are easy to work with, since this approach only requires you to configure Chunk Manager to resolve URLs to remote chunks, and the import function returns a simple promise. With chunks exported values. You can specify whether the chunks created by this approach should be a remote ones hosted on the server, on the internet or remote ones shipped together with main bundle inside the application. All of that makes Async chunks an ideal approach for modular applications, where the project consists of a single code base. This code snippet is a simplified version of a Elearning application, a module application. We use dynamic import function together with React lazy to create additional chunks and only load either of them based on the user role. The only thing necessary to use this approach is to configure chunk manager so that it knows where the chunks for the student and teacher will be later in production. Now with dynamic scripts. The second approach we are going on to a deeper water. Dynamic scripts are chunks with arbitrary code. The code that was created by the same or different bundler by the same or different team in house or externally with dependencies and coach sharing, or without any sharing at all. It's a powerful option, but with great power comes great responsibility, and you are responsible for putting it all together so that it works. If you want to share dependencies, you have to figure out exactly how you want to do it based on your project's needs and requirements. In this scenario, Repack gives you only low level APIs to implement user facing facade on top. This makes dynamic scripts approach more challenging, and it's recommended for more advanced users who already have experience with Webpack. This is the minimal example of how you could use dynamic scripts. It's a powerful tool, since you can load arbitrary code. Similarly to Async chunks, you need to configure chunk manager to specify where chunks are hosted, but you also need to manually trigger Loading of the chunks using load chunk method compared to Async chunks. The load chunk method is called manually here, but with Async chunks, it's been called under the hood automatically for you. And finally, we have Module Federation, the cherry on Top and Webpac's five new feature. What makes the Module Federation unique and exciting is the fact that it allows to create micro front ends, which can be developed in isolation by separate teams but ultimately create one big application. Module Federation. Similarly to dynamic scripts, allow you to create chunks also referred to as containers in separate dedicated compilations. This makes it great at scaling and give each team's ability to configure Web pack the way their chunk or container needs. However, they're the hardest to use and manage. Moreover, they require more elaborate quality assurance process to make sure that everything together works. As expected, module Federation is a great fit for super apps and mini app stores. Due to the isolation and scalability, each mini app can live in a dedicated code base and can have dedicated web app configuration. But when putting everything together, the main bundle in the host application can share and reuse dependencies with each mini app. This means that as long as the dependencies in host application and all of the mini apps are compatible based on somewhere, each dependency will be shared and no dependency will be duplicated. So Module Federation is rather new concept, and so the question arises is Module Federation available in repack today? And the answer is not yet, but it will. From the moment Repack was created, we had Module Federation support in mind, and since Module Federation and both Async chunks and dynamic scripts share internal logic, we are first focusing on delivering outstanding support for Async chunks and dynamic scripts and then tackling the big fish module Federation. So let's summarize the state of code splitting in Repack. The base implementation with Basic feature is already implemented. You can download and execute remote and local chunks. You can leverage basic caching and invalidation mechanism. You can provide custom URLs resolution logic for each remote chunk, and you can do all of that today, and there are more things to come from the upcoming bits. There are chunks signing and verification to tighten up the security even better and ensure the chunks the application is going to execute it's what it's supposed to be. Additionally, we have advanced Caching and advanced fetching options to support more variety of scenarios and infrastructures. Local assets support to allow to use static assets like images inside a remote chunk using a relative path and of course, more documentation and examples. This brings us to a conclusion you can start investigating and playing around with code splitting in Web Pack and repack. You can use Repack APIs to build great experiences on top of you can start migrating your project and investing into code splitting to later migrate to moderate Federation when it's available. However, keep in mind that code splitting support in repack is actively being worked on so the final shape and API might change and there are more features to come. So thank you for your time. I hope you enjoyed this introduction and I hope I was able to shed some light on code splitting landscape in React native ecosystem. And lastly, spark a light of curiosity. So stay tuned. There are more exciting things to come and thank you again.