<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Callstack Engineers</title>
    <description>The latest articles on DEV Community by Callstack Engineers (@callstackengineers).</description>
    <link>https://dev.to/callstackengineers</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F623378%2F12c5dee1-efe0-404d-8fe4-20130c332536.png</url>
      <title>DEV Community: Callstack Engineers</title>
      <link>https://dev.to/callstackengineers</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/callstackengineers"/>
    <language>en</language>
    <item>
      <title>A Step-By-Step Guide to Super App Development</title>
      <dc:creator>Callstack Engineers</dc:creator>
      <pubDate>Thu, 18 May 2023 10:34:17 +0000</pubDate>
      <link>https://dev.to/callstackengineers/a-step-by-step-guide-to-super-app-development-1gmm</link>
      <guid>https://dev.to/callstackengineers/a-step-by-step-guide-to-super-app-development-1gmm</guid>
      <description>&lt;p&gt;&lt;a href="https://www.callstack.com/blog-author/jakub-romanczyk"&gt;by Jakub Romańczyk&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the number of active mobile users growing and the consumers' demands for smooth mobile-first experiences strengthening each year, it’s no surprise you’re considering jumping on the super app bandwagon. After all, super apps come with &lt;a href="https://www.callstack.com/blog/super-app-business-faq?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Super_App_Guide"&gt;a number of benefits&lt;/a&gt; for both users and the businesses behind them.&lt;/p&gt;

&lt;p&gt;To help you take the first step, we’ve put together some tips for developing a super app from the tech perspective. As businesses and their products come in all shapes and sizes, we’re focusing here on two scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;building a super app from scratch,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;migrating your solutions to a super app setup.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Speaking of different shapes and sizes, when creating a super app, you can choose from a couple of different approaches, including: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Native Android application with Feature Delivery&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Native iOS application with WebViews&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cross-platform React Native application with Metro&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cross-platform React Native application with Webpack and Re.Pack&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article, we’ll be focusing on the latter, not only because we’re the people behind Re.Pack, but primarily because this solution allows you to enjoy the most benefits compared to other tools. Building your super app with Re.Pack means the ability to reuse features across apps, smaller JS bundle size, OTA updates, time and cost-effective development experience, and potential to leverage third-party contributors – these perks pretty much speak for themselves.&lt;/p&gt;

&lt;p&gt;Now let’s get down to the super app development business, shall we?&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a super app from scratch
&lt;/h2&gt;

&lt;p&gt;For the sake of this tutorial, we’ve prepared an example repository with two apps inside one monorepo, namely &lt;code&gt;HostApp&lt;/code&gt; and &lt;code&gt;MiniApp&lt;/code&gt;. You can find &lt;a href="https://github.com/callstack/super-app-example"&gt;the repository with the example here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;HostApp&lt;/code&gt; is a simple app with &lt;code&gt;HomeScreen&lt;/code&gt; and a &lt;code&gt;DetailScreen&lt;/code&gt;, which you can reach via a button on the &lt;code&gt;HomeScreen&lt;/code&gt;. &lt;code&gt;MiniApp&lt;/code&gt; is similar, but has a button that navigates to the &lt;code&gt;GalleryScreen&lt;/code&gt; with a list of pictures. &lt;/p&gt;

&lt;p&gt;For now, those are two separate apps that have nothing in common with each other and run independently. Each app has its own navigation with a few screens. Our goal in this part will be to bring the &lt;code&gt;MiniApp&lt;/code&gt; into the &lt;code&gt;HostApp&lt;/code&gt; using &lt;a href="https://www.callstack.com/blog/module-federation-with-re-pack-3?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Super_App_Guide"&gt;Re.Pack and Module Federation&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Why this combination of technologies? &lt;a href="https://www.callstack.com/open-source/re-pack?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Super_App_Guide"&gt;Re.Pack&lt;/a&gt; is an Open Source toolkit that allows you to build React Native apps with the support of the Webpack ecosystem. Thanks to supporting Module Federation ever since the 3.0 version, it’s particularly fit for developing mobile applications that benefit from &lt;a href="https://www.callstack.com/blog/implementing-code-splitting-in-react-native-with-re-pack?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Super_App_Guide"&gt;code splitting&lt;/a&gt; – and super apps are a great example of those. &lt;/p&gt;

&lt;p&gt;Now that you get the gist of using Re.Pack and Module Federation to build a super app, we can get to the nitty-gritty. Let’s get started by cloning the repository:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Setting up Re.Pack in both HostApp and MiniApp
&lt;/h2&gt;

&lt;p&gt;In both &lt;em&gt;packages/host-app and packages/mini-app&lt;/em&gt; install Re.Pack with its dependencies:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Make sure to run &lt;code&gt;yarn bootstrap&lt;/code&gt; from the repository's root to update the pods that come with those dependencies.&lt;/p&gt;

&lt;p&gt;Now let’s make some adjustments to the setup. To make React Native CLI able to use Re.Pack commands (such as &lt;code&gt;webpack-start&lt;/code&gt; or &lt;code&gt;webpack-bundle&lt;/code&gt;), we will add the following content to &lt;code&gt;react-native.config.js&lt;/code&gt; (or create it if it doesn't exist):&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Having done that, let’s update our &lt;code&gt;package.json&lt;/code&gt; scripts to reflect these changes. Edit the start script for both apps, so it utilizes new webpack-start command, which starts the development server for Re.Pack:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now add &lt;code&gt;webpack.config.mjs&lt;/code&gt; to each app in our monorepo. For now, we’ll start with a default template that will be modified along the way. You can find the &lt;a href="https://github.com/callstack/repack/blob/main/templates/webpack.config.mjs"&gt;ES Module template here&lt;/a&gt; or the &lt;a href="https://github.com/callstack/repack/blob/main/templates/webpack.config.cjs"&gt;CommonJS equivalent here&lt;/a&gt;. Either one will work just fine.&lt;/p&gt;

&lt;p&gt;The last step of this part is to modify the scripts used for bundling the iOS and Android.&lt;/p&gt;

&lt;p&gt;Open your application's XCode project/workspace and:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on the project in the Project navigator panel on the left&lt;/li&gt;
&lt;li&gt;Go to Build Phases tab&lt;/li&gt;
&lt;li&gt;Expand Bundle React Native code and images phase&lt;/li&gt;
&lt;li&gt;Add export BUNDLE_COMMAND=webpack-bundle to the phase
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Go to &lt;code&gt;android/app/build.gradle&lt;/code&gt; in both apps, uncomment the line with &lt;code&gt;bundleCommand&lt;/code&gt; in the react block, and modify it to use &lt;code&gt;webpack-bundle&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;That’s the basic setup for Re.Pack; try running the apps to see if everything works as expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up ModuleFederationPlugin
&lt;/h3&gt;

&lt;p&gt;Now it’s time to set up the &lt;code&gt;ModuleFederationPlugin&lt;/code&gt;. Not long ago, you were required to do some hacky workarounds to get the Module Federation working with Re.Pack. Since the release of version 3.0, though, the &lt;code&gt;ModuleFederationPlugin&lt;/code&gt; has been included out of the box. &lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/zWQ-WfVxs-8"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Let’s add a new instance of &lt;code&gt;RePack.ModuleFederationPlugin&lt;/code&gt; to our &lt;code&gt;webpack.config&lt;/code&gt; in the &lt;code&gt;HostApp&lt;/code&gt;: &lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We’ve added all our dependencies because they all have native code inside, and whenever a dependency has native parts, you must add it to the shared field inside &lt;code&gt;ModuleFederationPlugin&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Usually, when a node module contains &lt;code&gt;android&lt;/code&gt; and/or &lt;code&gt;ios&lt;/code&gt; directories, you should consider it native. When it comes to dependencies with only JavaScript in them, you can leave them out, and Re.Pack will take care of downloading them from the mini app. However, it is advised to also include them as you will reduce the overall network transfer when loading the bundles. &lt;/p&gt;

&lt;p&gt;We’ve also specified &lt;code&gt;singleton&lt;/code&gt; and &lt;code&gt;eager&lt;/code&gt; on them. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;Singleton&lt;/code&gt; means that only one instance of such a module will ever be initialized, which is a requirement for React and React Native. It is usually a good idea to make the dependencies with native parts &lt;code&gt;singleton&lt;/code&gt; as well. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;Eager&lt;/code&gt;, on the other hand, means that the module is added to the initial bundle and will not be loaded later. All shared modules in the host app should be &lt;code&gt;eager&lt;/code&gt;. In remote containers, it depends on the build configuration. When you want to run the app as a standalone, you need to mark all the shared dependencies as &lt;code&gt;eager&lt;/code&gt; as well.&lt;/p&gt;

&lt;p&gt;Having that in mind, let's add a similar configuration of the plugin to the mini app:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Inside webpack.config.mjs, let’s grab &lt;code&gt;STANDALONE&lt;/code&gt; from the process.env&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Now let’s add the &lt;code&gt;ModuleFederationPlugin&lt;/code&gt; just like in the &lt;code&gt;HostApp&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally, let’s add a separate script to run webpack in our mini app in standalone mode and modify the previous start script to run on a different port (which will come in handy soon when we need to have both our development servers running at the same time)&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;STANDALONE&lt;/code&gt; env variable will help us to distinguish when we want to run the app as a separate entity or as a mini app. Currently, modules specified in &lt;code&gt;shared&lt;/code&gt; will be eagerly loaded only when running the app on its own.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up ScriptManager in the HostApp
&lt;/h3&gt;

&lt;p&gt;The last part of the setup to get the &lt;code&gt;HostApp&lt;/code&gt; ready to accept remote containers is to add the &lt;code&gt;ScriptManager&lt;/code&gt;’s resolver. We need to tell our app where to find the mini app, and we’re about to do it now. &lt;/p&gt;

&lt;p&gt;Let’s add the following piece in the &lt;code&gt;HostApp’s index.js&lt;/code&gt; on line 4 &lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As &lt;code&gt;ScriptManager&lt;/code&gt; can have many resolvers, we need to return the configuration for the bundle only if we get a URL match. Implicitly returning undefined here means the &lt;code&gt;ScriptManager&lt;/code&gt; should keep looking at other resolvers to find a proper match. In the example, the configuration contains info about the URL and platform, but many more options are available for the more advanced use cases.&lt;/p&gt;

&lt;p&gt;Our basic Module Federation setup is now complete, and we can start connecting the two apps.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using MainNavigator from the &lt;code&gt;MiniApp&lt;/code&gt; in the &lt;code&gt;HostApp&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;In this part, we will be going through the process of reusing the whole &lt;code&gt;MiniApp&lt;/code&gt; inside our &lt;code&gt;HostApp&lt;/code&gt;. The part we will need is the &lt;code&gt;MainNavigator&lt;/code&gt; from the &lt;code&gt;MiniApp&lt;/code&gt;, as we don’t want to have two &lt;code&gt;NavigationContainers&lt;/code&gt; in our app. &lt;/p&gt;

&lt;p&gt;First, we must expose the &lt;code&gt;MainNavigator&lt;/code&gt; from the &lt;code&gt;MiniApp&lt;/code&gt; to be available for consumption in the &lt;code&gt;HostApp&lt;/code&gt;. Let’s go to MiniApp’s &lt;code&gt;webpack.config.mjs&lt;/code&gt; and expose it there:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You can expose the components to be consumed by adding them in the form of key-value pairs, where the key is the name used to refer to that component in the &lt;code&gt;HostApp&lt;/code&gt;, and the value is the path to the component. Note that for this to work, we must use &lt;code&gt;export default&lt;/code&gt; in our component.&lt;/p&gt;

&lt;p&gt;Once we’re done with that, it’s time to import the &lt;code&gt;MiniApp&lt;/code&gt; into the &lt;code&gt;HostApp&lt;/code&gt;. Let’s create a new screen that will house the &lt;code&gt;MainNavigator&lt;/code&gt; from the &lt;code&gt;MiniApp&lt;/code&gt;: &lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;Federated.importModule&lt;/code&gt; takes two parameters: the name of the container and the name of the component that we want to import. As we want to load the component only when the user enters that particular screen, we need to put the import inside &lt;code&gt;React.lazy&lt;/code&gt; and render it within &lt;code&gt;React.Suspense&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To finish up, let’s add the &lt;code&gt;MiniAppScreen&lt;/code&gt; to the &lt;code&gt;MainNavigator&lt;/code&gt; in the &lt;code&gt;HostApp&lt;/code&gt; and add a button to navigate to &lt;code&gt;MiniAppScreen&lt;/code&gt; inside &lt;code&gt;HomeScreen&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now we should have a working &lt;code&gt;MiniApp&lt;/code&gt; inside our &lt;code&gt;HostApp&lt;/code&gt;. Go ahead and start both development servers using &lt;code&gt;yarn start&lt;/code&gt; command in the root of the repository, and then let’s run the host app. If you choose to run the app on Android, remember to expose the port on the Android emulator to your machine by running:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Click on the newly added button to Navigate to MiniApp and enjoy your super app!&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/LR7Kf16ptrQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;It’s easy to notice that after navigating to the &lt;code&gt;MiniApp&lt;/code&gt;, we end up with two navigation headers. We can fix that by adjusting the header in the &lt;code&gt;HostApp&lt;/code&gt; or exposing a navigator without the header; the decision is up to you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migrating to a super app setup
&lt;/h2&gt;

&lt;p&gt;Migrating to a super app setup requires careful consideration and planning. Upgrading your existing setup with Re.Pack and Module Federation, as we’ve described above, shouldn’t pose problems in itself. However, it may become challenging in the context of your current project and the custom solutions it involves. In this part, we look at such challenges and cover a few key things to consider when turning your product into a super app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Aligning dependencies
&lt;/h3&gt;

&lt;p&gt;If you’re considering enriching your product portfolio with a super app, your codebase is probably already large enough to contain many dependencies. The biggest challenge lies in aligning the dependencies between respective apps, so they can be shared as efficiently as possible.&lt;/p&gt;

&lt;p&gt;If there is an issue with one library or component, the federated module could suffer misaligned versions of libraries in the host app. Some tolerance is involved, as Re.Pack will try to fetch the missing dependencies by default, and runtime errors might not be the case. At the end of the day, however, Re.Pack will complain about version requirements not being met, albeit in development mode. &lt;/p&gt;

&lt;p&gt;When the package contains native code and the versions are not aligned, a runtime error will occur. To avoid that, it is a good idea to have an error boundary wrapper that prevents federated modules from crashing your host app and displays fallback components when such issues arise.&lt;/p&gt;

&lt;h3&gt;
  
  
  Assets handling
&lt;/h3&gt;

&lt;p&gt;Another thing that’s vital to successfully migrating your app is handling the assets. When the mini app is embedded into the host app, it won’t be able to access its local assets, as they won’t be added to the host app asset’s registry in build time. You need to remember that this problem won’t manifest itself in development mode with dev-server – only when working with a static bundle produced by the &lt;code&gt;react-native webpack-bundle&lt;/code&gt; command. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/callstack/repack"&gt;‍Re.Pack&lt;/a&gt; offers two ways to deal with that. The first one, and by far the preferred one, is to &lt;strong&gt;handle the assets just like we do on the web&lt;/strong&gt;, where our assets are first uploaded to a remote server (preferably CDN) first, and only then can be downloaded by the users. Re.Pack provides allows you to gather all the assets and modify the final bundle so that the production build can download them on demand.&lt;/p&gt;

&lt;p&gt;These assets are now remote, so it might be necessary to include a placeholder to display while loading them. When working with remote assets, the only limitation is that the hostname of your CDN needs to be known at build time, so Re.Pack can generate the URLs for these assets.&lt;/p&gt;

&lt;p&gt;Another alternative to consider is &lt;strong&gt;inlining all the assets from the federated module, so they are downloaded with the bundle itself&lt;/strong&gt;. You can do that by adjusting the &lt;code&gt;assetLoader&lt;/code&gt;’s options in the &lt;code&gt;webpack.config.mjs&lt;/code&gt;, namely: setting inline to true. This solution has one major drawback: it significantly increases the bundle size. You might consider inlining some assets if you don’t want them to be publicly accessible on the web, or they are vital to a swift startup of your mini app, as they will be instantly visible to the user.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sharing state across the app
&lt;/h3&gt;

&lt;p&gt;When trying to create a super app from an existing app by extracting a certain functionality to a mini app, state management might become an issue. Until now, the state has been tightly coupled with the whole app. If you want your mini app to be a consumer of that state, it is necessary to address that problem. &lt;/p&gt;

&lt;p&gt;For the sake of this example, let’s assume we have a setup like in the first part of the article. To make our state management solution reusable across the board with mini apps and the host app, we could extract the shared state into a separate package. Depending on whether you would like to update the state part of the app over-the-air, you could make it into a federated module as well. Otherwise, this can be a statically imported module into both the host app and the mini app. &lt;/p&gt;

&lt;p&gt;If we specify this module inside the &lt;code&gt;shared&lt;/code&gt; portion of the Re.Pack’s &lt;code&gt;ModuleFederationPlugin&lt;/code&gt;, we will only have one copy of that module during the runtime of our super app. If that’s the case, we will be able to place the &lt;code&gt;ContextProvider&lt;/code&gt; component in the host app and access the same instance in our mini app, having a shared state across the whole app.&lt;/p&gt;

&lt;p&gt;These are just a few examples of challenges you might face when migrating to a super app setup. It’s hard to tell what you might run into, as every app is unique in its own way. Mind that Module Federation has been present in the web environment for quite some time, so if your problem is strictly related to the JS part of the app, chances are someone solved a similar problem already, and the concept might be applicable in the context of super apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;We hope this article has shed more light on what it takes to develop a super app from the tech standpoint. Whether you’re up for building a super app from scratch or migrating your current solution into such a setup, it might turn out that your team needs some help to do it right. That’s why we’ve prepared &lt;a href="https://github.com/callstack/super-app-template"&gt;a super-app-showcase&lt;/a&gt;. Use it to your advantage, and don’t hesitate to reach out to us if you have any questions about &lt;a href="https://www.callstack.com/super-app-development?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Super_App_Guide"&gt;super app developmen&lt;/a&gt;t.&lt;/p&gt;

&lt;p&gt;If you’re looking for more organizational tips, we’ve also got you covered with a blog post about &lt;a href="https://www.callstack.com/blog/optimize-development-efficiency-when-building-super-app?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Super_App_Guide"&gt;developer experience and planning the work of your in-house team and third-party contributors&lt;/a&gt;. We’ve also published &lt;a href="https://www.callstack.com/blog/case-study-super-app-template?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Super_App_Guide"&gt;a case study of a super-app-showcase&lt;/a&gt; that might significantly speed up your work.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was originally published at &lt;a href="https://www.callstack.com/blog/step-by-step-guide-to-super-app-development?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Super_App_Guide"&gt;callstack.com&lt;/a&gt; on April 12, 2023.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>superapp</category>
      <category>reactnative</category>
      <category>repack</category>
    </item>
    <item>
      <title>Working With the Super-App-Showcase Repository</title>
      <dc:creator>Callstack Engineers</dc:creator>
      <pubDate>Thu, 18 May 2023 09:09:16 +0000</pubDate>
      <link>https://dev.to/callstackengineers/working-with-the-super-app-showcase-repository-3bcb</link>
      <guid>https://dev.to/callstackengineers/working-with-the-super-app-showcase-repository-3bcb</guid>
      <description>&lt;p&gt;&lt;a href="https://www.callstack.com/blog-author/jakub-romanczyk"&gt;by Jakub Romańczyk&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.callstack.com/blog?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Super_App_Repo"&gt;On Callstack blog&lt;/a&gt;, you’ll find tips for building a super app and maximizing the efficiency of the development process in such setup. To give you even more insights into what super app development is all about, we’ve put together a case study of the super-app-showcase, a prime example of a repository demonstrating how to structure a super app when working with &lt;a href="https://www.callstack.com/open-source/re-pack?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Super_App_Repo"&gt;Re.Pack&lt;/a&gt; effectively. &lt;/p&gt;

&lt;p&gt;Building upon the tutorial found in &lt;a href="https://www.callstack.com/blog/step-by-step-guide-to-super-app-development?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Super_App_Repo"&gt;this step-by-step guide to super app development&lt;/a&gt;, where we showcased the bare minimum to illustrate super app development principles, this case study presents a more robust example that could evolve into a production-ready super app. &lt;/p&gt;

&lt;p&gt;By analyzing this showcase, we can gain valuable insights into the solutions implemented to tackle various challenges developers face while creating a super app. By exploring the intricacies of this showcase, we mean to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;provide an overview of the general architecture of the solution, &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;set the stage for a deeper understanding of each component's role in creating a seamless and efficient super app,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;empower you to deal with super apps more effectively in your projects.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architecture overview
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--F5RKwbyo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tcqsm72cbfhmb3jejhx9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--F5RKwbyo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tcqsm72cbfhmb3jejhx9.png" alt="Image description" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/callstack/super-app-template"&gt;super-app-showcase repository&lt;/a&gt; incorporates a micro-frontend architecture, facilitating easy setup and maintenance of the contained apps. These apps can be deployed independently or as part of the super app, providing developers with flexibility and fostering efficient collaboration.&lt;/p&gt;

&lt;p&gt;The super-app-showcase is composed of the host app, which functions as the main container for all the micro-frontends, and the shell app, which acts as a blueprint of the host app with shared dependencies. Among other apps, you’ll find booking, shopping, news, and dashboard, each representing a micro-frontend for their respective services. An additional auth module is exposed for other modules to implement authentication and authorization flows, and UI.&lt;/p&gt;

&lt;p&gt;Each of the mini apps, such as booking, shopping, news, and dashboard, exposes a &lt;code&gt;MainNavigator&lt;/code&gt;, representing the mini app itself. In the case of the booking app, an additional &lt;code&gt;UpcomingAppointments&lt;/code&gt; screen is exposed, which is used within the super app as part of its navigation. The news mini app is stored in a separate repository to demonstrate the usage of a remote container outside the monorepo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monorepo
&lt;/h2&gt;

&lt;p&gt;As the team behind the &lt;a href="https://github.com/callstack/super-app-template"&gt;super-app-showcase&lt;/a&gt;, we decided to go with a monorepo, but we need to emphasize that it's a strategic choice and not a strict requirement. There are both pros and cons to consider regarding this solution.&lt;/p&gt;

&lt;p&gt;One of the major advantages of using a monorepo is that it &lt;strong&gt;simplifies dependency management&lt;/strong&gt;. In our case, we've set up a &lt;code&gt;shared&lt;/code&gt; directory in the root of the monorepo containing a JSON file with shared dependencies for the Module Federation. This approach makes it easy for developers to maintain the most vital part of the Re.Pack’s Module Federation Plugin.&lt;/p&gt;

&lt;p&gt;Furthermore, a monorepo enhances code sharing, &lt;strong&gt;improving code reusability and consistency across the project&lt;/strong&gt;. For instance, a monorepo enables us to enforce linting rules and formatting throughout the entire codebase, ensuring a uniform code style. This can significantly benefit development teams looking to maintain a clean and coherent codebase.&lt;/p&gt;

&lt;p&gt;As mentioned previously, the news mini app is stored in a separate repository. This demonstrates that the entire app could have been structured using individual repositories instead of a monorepo, which might suit some projects better. Ultimately, &lt;strong&gt;the decision to use a monorepo or separate repositories should be based on your development team's specific needs and preferences&lt;/strong&gt;, keeping in mind the unique aspects of each project. It's crucial to weigh the pros and cons, such as potential scalability issues and challenges in managing a large codebase, when deciding whether a monorepo is the right choice for your project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Catalog server
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/callstack/super-app-template"&gt;super-app-showcase&lt;/a&gt; includes a package within the monorepo named &lt;code&gt;catalog-server&lt;/code&gt;, which plays a vital role in handling mini app compatibility in production environments. Built using Node.js and Express, this straightforward server acts as a reliable resource for determining which mini app version to download considering the requesting app's requirements, such as its current version.&lt;/p&gt;

&lt;p&gt;Centralizing versioning logic in the &lt;code&gt;catalog-server&lt;/code&gt; allows developers to easily implement custom versioning strategies, ensuring &lt;strong&gt;seamless integration between the host app and its corresponding mini apps&lt;/strong&gt;. This approach is fundamental when dealing with conflicts arising from native dependencies. When a new version of the host app is released, users who are still on an older version of the host app should not download the latest mini app that requires the newest native changes. Instead, the &lt;code&gt;catalog-server&lt;/code&gt; ensures they download the most recent, compatible version that guarantees a smooth experience.&lt;/p&gt;

&lt;p&gt;By managing version compatibility this way, the &lt;code&gt;catalog-server&lt;/code&gt; effectively mitigates potential issues arising from different host app versions and provides seamless integration between the host app and its corresponding mini apps, maintaining the stability of the super app.&lt;/p&gt;

&lt;h2&gt;
  
  
  State management
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;auth&lt;/code&gt; package in our super-app-showcase monorepo is a practical solution for state management, focusing on authentication and authorization for all mini apps. Keep in mind that this package isn't meant to work as a standalone module. Instead, it serves as a collection of components designed to handle authentication and authorization within the super app.&lt;/p&gt;

&lt;p&gt;This package makes it easy for developers to integrate authentication and authorization flows into their super app. Although it doesn't have dedicated iOS or Android folders, it relies on the host app bundle for any necessary native-based libraries.&lt;/p&gt;

&lt;p&gt;What's great about the &lt;code&gt;auth&lt;/code&gt; package is its reusability. When mini apps are run independently, they can use their own provider component for authentication and authorization. But when they're part of the host app, they can efficiently use the provider component from the host app itself. This approach not only &lt;strong&gt;simplifies the development process&lt;/strong&gt; but also &lt;strong&gt;ensures a consistent and secure user experience&lt;/strong&gt; across the entire super app.&lt;/p&gt;

&lt;p&gt;The package can be viewed as a template for implementing reusable state management solutions in super apps using any library of your choice. By following the design principles demonstrated in the auth package, developers can create their own custom state management solutions tailored to their specific needs and preferences while maintaining the same level of reusability and consistency throughout the super app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shell app
&lt;/h2&gt;

&lt;p&gt;The shell app, although not strictly required, serves as a helpful addition to the host app by precisely representing its structure and navigation. To maintain its usefulness, it should be kept in sync with the host app. The shell app's lightweight design trims the excess, focusing on the aspects needed for integration. It may even feature pre-configured states for hassle-free testing of different aspects. This effective testing process allows developers to pinpoint and tackle integration challenges early on, resulting in an overall more stable super app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The super-app-showcase serves as a comprehensive guide to &lt;a href="https://www.callstack.com/blog/super-app-business-faq?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Super_App_Repo"&gt;building a robust and scalable super app&lt;/a&gt; using &lt;a href="https://www.callstack.com/podcasts/module-federation?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Super_App_Repo"&gt;Re.Pack and Module Federation&lt;/a&gt;. By exploring its monorepo structure, &lt;code&gt;catalog-server&lt;/code&gt;, basic state management solution we've highlighted various solutions and best practices that developers can employ to tackle challenges and streamline the development process. &lt;/p&gt;

&lt;p&gt;By understanding the architectural choices, such as monorepo versus separate repositories, and leveraging shared components and state management, you can create powerful super apps that offer a consistent and seamless user experience. Armed with this knowledge, you are now better equipped to navigate the world of super app development and bring your own super app projects to life. And if you’re looking for an experienced tech partner to &lt;a href="https://www.callstack.com/super-app-development?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Super_App_Repo"&gt;help you with super app development&lt;/a&gt;, get in touch with our team.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was originally published at &lt;a href="https://www.callstack.com/blog/case-study-super-app-template?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Super_App_Repo"&gt;callstack.com&lt;/a&gt; on April 12, 2023.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>superapp</category>
      <category>reactnative</category>
      <category>repack</category>
    </item>
    <item>
      <title>How to Optimize Development Efficiency When You’re Building a Super App</title>
      <dc:creator>Callstack Engineers</dc:creator>
      <pubDate>Thu, 18 May 2023 08:49:45 +0000</pubDate>
      <link>https://dev.to/callstackengineers/how-to-optimize-development-efficiency-when-youre-building-a-super-app-nci</link>
      <guid>https://dev.to/callstackengineers/how-to-optimize-development-efficiency-when-youre-building-a-super-app-nci</guid>
      <description>&lt;p&gt;&lt;a href="https://www.callstack.com/blog-author/jakub-romanczyk"&gt;by Jakub Romańczyk&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The modular architecture of super apps translates into significant benefits for their creators. Enriching your product portfolio with a super app ultimately means greater flexibility, &lt;a href="https://www.callstack.com/blog/super-app-business-faq?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Optimize_Development_Efficiency"&gt;more sustainable growth&lt;/a&gt;, and increased development efficiency. However, to enjoy these benefits, you need to plan the development process well – and in this article, we’re going to show you how to take care of that. &lt;/p&gt;

&lt;p&gt;We’ll take a closer look at two factors that have the potential to boost the efficiency of your super app development process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;preparing for third-party contributions,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;laying the foundations for smooth teamwork.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re looking for practical tips on developing a super app, check out &lt;a href="https://www.callstack.com/blog/step-by-step-guide-to-super-app-development?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Optimize_Development_Efficiency"&gt;this guide to super app development&lt;/a&gt; and &lt;a href="https://www.callstack.com/blog/case-study-super-app-template?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Optimize_Development_Efficiency"&gt;a case study of our super-app-showcase&lt;/a&gt;. For now, though, let’s focus on the organizational side of this process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing your super app for third-party contributions
&lt;/h2&gt;

&lt;p&gt;Super apps’ architecture enables third-party contributions to be seamlessly integrated into an app. In practice, it means you’re capable of developing certain features faster and more efficiently by leveraging the expertise and capabilities of an external team. &lt;/p&gt;

&lt;p&gt;While it sounds promising, you need to be cautious and thoroughly vet the third-party engineers you choose to work with, as the app will run in the same JavaScript context with their code, potentially posing a security risk. In this part of the article, we discuss a few things to consider when opening up your app for third-party contributions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Laying down requirements
&lt;/h3&gt;

&lt;p&gt;First and foremost, you need to set out requirements for the mini apps. It is absolutely necessary to specify what &lt;strong&gt;version of React and React Native&lt;/strong&gt; the mini app is supposed to use, and this requirement needs to be kept in sync with the host app at all times.&lt;/p&gt;

&lt;p&gt;If the mini app is going to use a &lt;a href="https://www.callstack.com/training/working-with-native-modules?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Optimize_Development_Efficiency"&gt;native module&lt;/a&gt;, it is also necessary to declare this upfront and add it to the host app to ensure that everything works as expected. It might be useful to establish a communication channel when a native dependency needs to be added to the host app so that the super app team can quickly approve or reject the proposed change. &lt;/p&gt;

&lt;p&gt;Besides the setup requirements, it's also a good idea to provide &lt;strong&gt;a design rule book or a shared UI components library&lt;/strong&gt; that the third-party developers must use when building their features so that the app is coherent as a whole.&lt;/p&gt;

&lt;h3&gt;
  
  
  Optimizing developer experience
&lt;/h3&gt;

&lt;p&gt;To provide a great development experience that will minimize integration issues and possibly enforce some requirements mentioned above, consider &lt;strong&gt;creating and exposing a sandbox environment that closely resembles your host app&lt;/strong&gt;. This way, the team working on the mini app can ensure everything is well-aligned. It proves particularly useful when the host app is being upgraded to a &lt;a href="https://www.callstack.com/blog/always-run-the-latest-version-of-react-native?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Optimize_Development_Efficiency"&gt;new version of React Native&lt;/a&gt;, allowing each team to independently upgrade their respective mini apps.&lt;/p&gt;

&lt;h3&gt;
  
  
  SDK
&lt;/h3&gt;

&lt;p&gt;If you want your third-party mini-app to be consistent with the overall app's design and/or communicate with the host app, you should consider creating an SDK in the form of a dependency added to the mini-app. &lt;/p&gt;

&lt;p&gt;An SDK can provide some common components, such as loading indicators or navigation headers. It can also expose methods to access the host app’s state (e.g., redux selectors) or even basic tools for developers like an ESLint preset. Remember that the SDK contents depend on the details of your setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mobile nuances
&lt;/h3&gt;

&lt;p&gt;Last but not least, don’t forget that the mobile environment differs from the web. If you plan on integrating big new functionality with your app, you need to go through the App Store or Google Play Store review process again to audit that functionality. Omitting this step may result in your app being removed from the store altogether. &lt;/p&gt;

&lt;p&gt;As you can see, enabling third-party contributions in your super app will require some effort on your end. We haven’t mentioned here the delivery-related matters, as they’re even more specific to your own setup. Still, the ideas discussed in this section will be helpful if you decide to outsource some of the feature work to external teams.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fostering collaboration between teams working on your super app
&lt;/h2&gt;

&lt;p&gt;The super app approach enables teams to split their work while maintaining a coherent application, which is critical when multiple teams work on different parts of a single application or system. &lt;/p&gt;

&lt;p&gt;Respective squads can independently develop and deploy parts of an application as mini apps: standalone modules that provide specific functionality or user interface components. They can be hosted and deployed autonomously (to a certain extent) while seamlessly integrating into the larger super app. In day-to-day work, this allows teams to &lt;strong&gt;collaborate more efficiently&lt;/strong&gt; by reducing inter-team dependencies and enabling them to focus on their specific areas of expertise. In this part of the article, we explain how to make this teamwork as smooth as possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sustainable architecture
&lt;/h3&gt;

&lt;p&gt;The most common trend when splitting a monolith app into micro frontends is to divide the app into separate features. Separating the app screen by screen is overkill and should be avoided. Instead, we recommend identifying the core functional areas or features that can be developed and managed independently. &lt;/p&gt;

&lt;p&gt;This will create a more sustainable architecture, allowing for &lt;strong&gt;more effortless scalability and efficient development cycles&lt;/strong&gt;. By focusing on feature-based divisions, teams can optimize work, reduce communication overhead, and streamline project organization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lightweight host app
&lt;/h3&gt;

&lt;p&gt;To ensure a seamless developer experience, creating a lightweight version of the host app is advisable solely for integration purposes. This stripped-down version should provide a basic scaffolding, enabling mini apps to be embedded in the same context as the host app. Keeping this version up to date with the host app is crucial, particularly with regard to dependencies and the component tree. &lt;/p&gt;

&lt;p&gt;Although this may seem like a labor-intensive process, maintaining the lightweight version is typically only necessary when core changes occur in the host app, such as dependency upgrades or interface changes. This approach allows developers to test and debug their mini apps more efficiently in an environment that closely resembles the final super app, promoting &lt;strong&gt;better collaboration and minimizing integration issues&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monorepo
&lt;/h3&gt;

&lt;p&gt;Another optional strategy for managing super app development is organizing the codebase into a monorepo. By keeping all code in one central repository, teams can more easily &lt;strong&gt;share code, enforce consistent coding standards, and manage dependencies between projects&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Nevertheless, managing a monorepo can be difficult, as it requires careful attention to how different projects interact with one another. Bear in mind that the independence granted by Module Federation could be limited when adopting a monorepo, as it brings the codebase together. &lt;/p&gt;

&lt;p&gt;To make the most of a monorepo, teams should establish clear guidelines for how code is structured and shared, leverage automation for streamlining development and testing processes, and maintain a strong focus on communication and collaboration across the entire team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Building a super app using &lt;a href="https://www.callstack.com/blog/module-federation-with-re-pack-3?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Optimize_Development_Efficiency"&gt;Re.Pack and Module Federation&lt;/a&gt; can be a complex endeavor, with numerous aspects to consider when dividing work among development teams. To successfully navigate this process, it is crucial to carefully evaluate various strategies and tailor them to the project's unique requirements. &lt;/p&gt;

&lt;p&gt;We’ve presented here several ideas to help guide the decision-making process, but you need to remember that there is no one-size-fits-all solution. Ultimately, effective communication, collaboration, and adaptability are key factors in addressing the challenges of super app development and ensuring a seamless end product.&lt;/p&gt;

&lt;p&gt;‍If you need help navigating through the &lt;a href="https://www.callstack.com/super-app-development?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Optimize_Development_Efficiency"&gt;super app development process&lt;/a&gt;, give us a shout, we’ll be happy to help.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was originally published at &lt;a href="https://www.callstack.com/blog/optimize-development-efficiency-when-building-super-app?utm_campaign=super_apps&amp;amp;utm_source=dev.to&amp;amp;utm_content=Optimize_Development_Efficiency"&gt;callstack.com&lt;/a&gt; on April 12, 2023.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>superapp</category>
      <category>productivity</category>
      <category>productdevelopment</category>
    </item>
    <item>
      <title>Migrating a React Native Library to the New Architecture</title>
      <dc:creator>Callstack Engineers</dc:creator>
      <pubDate>Mon, 14 Nov 2022 13:07:18 +0000</pubDate>
      <link>https://dev.to/callstackengineers/migrating-a-react-native-library-to-the-new-architecture-54e2</link>
      <guid>https://dev.to/callstackengineers/migrating-a-react-native-library-to-the-new-architecture-54e2</guid>
      <description>&lt;p&gt;by Oskar Kwaśniewski&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This article is a bird's-eye view of migrating a React Native library to the New Architecture. At first, I wanted to go into the details. However, due to the pace of changes and ever-evolving new patterns, I decided to walk you through the migration steps with the helpful resources I found.&lt;/p&gt;

&lt;p&gt;I had the pleasure of working on migrating &lt;a href="https://github.com/callstack/react-native-slider/releases/tag/v4.3.0"&gt;react-native-slider&lt;/a&gt; and also the Android part of &lt;a href="https://github.com/callstack/react-native-pager-view"&gt;react-native-pager-view&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s the New Architecture?
&lt;/h2&gt;

&lt;p&gt;If you are following things that happen in the React Native world, I’m sure you heard about the New Architecture, including Fabric and Turbo Modules.&lt;/p&gt;

&lt;p&gt;If you are new to the “New Architecture” world, check out Lorenzo's at React Native Wrocław Meetup this year.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/sdQHzjV90ow"&gt;https://youtu.be/sdQHzjV90ow&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is also a &lt;a href="https://www.callstack.com/podcasts/react-native-new-architecture-ep-17"&gt;podcast episode on the New Architecture&lt;/a&gt; in which &lt;a href="https://www.callstack.com/team/lukasz-chludzinski"&gt;Łukasz Chludziński&lt;/a&gt; talks with &lt;a href="https://twitter.com/cortinico"&gt;Nicola Corti&lt;/a&gt;, a member of the React Native core team.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s Fabric?
&lt;/h2&gt;

&lt;p&gt;Fabric is React Native's &lt;strong&gt;new concurrent rendering system&lt;/strong&gt;, a conceptual evolution of the legacy render system. It allows for all the features React 18+ brings to the table. Fabric is one of the 4 pillars of the New Architecture that React Native core team is working on since 2018.&lt;/p&gt;

&lt;p&gt;Thanks to Fabric, instead of using the bridge which communicated with serialised JSON messages, we can communicate using JSI (second pillar), which is a C++ API for interacting with any JS engine. Ultimately JSI is going to replace the bridge (it’s the “bridgeless” project) but for now they live side by side, which is good because it can speed up your migration when you stumble upon some edge case which is not supported yet.&lt;/p&gt;

&lt;p&gt;The third pillar is Turbo Modules. It’s an interface on top of JSI, that leverages CodeGen (the last pillar) to generate C++ code from our TypeScript or Flow spec.&lt;/p&gt;

&lt;p&gt;If you want to try out the new Architecture in your app make sure to follow this &lt;a href="https://reactnative.dev/docs/new-architecture-app-intro"&gt;guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps to migrate a library
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Writing TypeScript spec for Codegen&lt;/li&gt;
&lt;li&gt;Migrating deprecated JavaScript APIs&lt;/li&gt;
&lt;li&gt;Extending &lt;code&gt;react-native-codegen&lt;/code&gt; generated interfaces on native platforms (Android / iOS)&lt;/li&gt;
&lt;li&gt;Done ✅&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This may seem like a lot of work but with the documentation getting better and more developers getting involved in the process, it becomes easier every day. It is also worth noting that the first two steps can be done even before migrating to the New Architecture - when preparing your library for migration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using an official migration guide for library creators
&lt;/h2&gt;

&lt;p&gt;There is an official migration guide that you can follow: &lt;a href="https://github.com/react-native-community/RNNewArchitectureLibraries"&gt;React Native New Architecture Libraries&lt;/a&gt;. It has examples creating simple Fabric component and also a Turbo Module. There is also &lt;a href="https://github.com/react-native-community/RNNewArchitectureLibraries"&gt;another guide&lt;/a&gt; for migrating your whole app to the New Architecture.&lt;/p&gt;

&lt;p&gt;These examples really help to get you going with the migration. However, most of the time you will end up browsing the source code of other libraries (at least I did). So another helpful resource is a &lt;a href="https://github.com/react-native-community/RNNewArchitectureApp"&gt;list of already migrated libraries&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a library from scratch
&lt;/h2&gt;

&lt;p&gt;If you want to create a new library or just &lt;strong&gt;scaffold a New Architecture setup&lt;/strong&gt; for your existing library, you can use &lt;a href="https://github.com/callstack/react-native-builder-bob"&gt;react-native-builder-bob&lt;/a&gt; which recently received a lot of new features!&lt;/p&gt;

&lt;p&gt;Here is a screenshot of scaffolding a new library with &lt;code&gt;create-react-native-library&lt;/code&gt;. As you can see, there are new options for Turbo Modules.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jzFsmIL1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4s4mbcsut6mmoqtgmk12.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jzFsmIL1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4s4mbcsut6mmoqtgmk12.jpeg" alt="Image description" width="800" height="351"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have used it to scaffold the New Architecture inside &lt;code&gt;react-native-pager-view&lt;/code&gt; which was way faster than creating all the necessary setup by hand. Fabric support will be added soon, but it may be already there as you are reading the article 😄 So go ahead and give Bob a try!&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Writing TypeScript spec
&lt;/h2&gt;

&lt;p&gt;Now let’s &lt;strong&gt;start with the migration part&lt;/strong&gt;. The goal of this step is to write a specification of your module which is a &lt;strong&gt;set of types written in Flow or TypeScript&lt;/strong&gt; that defines all the APIs provided by the native module. Using a spec allows Codegen (code generation tool for React Native) to generate native code for each platform during build time. To find more about it, refer to the &lt;a href="https://reactnative.dev/docs/new-architecture-library-intro#writing-the-javascript-spec"&gt;docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is how the generated files look like for Android.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--z6jxmUMe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/68gv1z4j1231mcf885z8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z6jxmUMe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/68gv1z4j1231mcf885z8.png" alt="Image description" width="800" height="328"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It sounds so good in theory. In reality, however, not everything is working as expected (yet!). Let’s go over a few issues I’ve stumbled upon.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unsupported props between platforms&lt;/strong&gt;&lt;br&gt;
As for now CodeGen doesn’t support platform specific specs, so keep in mind that you need to define types for every platform in your spec file. If you have any props that’s not supported on iOS it’s not a problem because you can skip it inside &lt;code&gt;updateProps&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- (void)updateProps:(const Props::Shared &amp;amp;)props oldProps:(const Props::Shared &amp;amp;)oldProps
{
    const auto &amp;amp;oldScreenProps = *std::static_pointer_cast&amp;lt;const RNCSliderProps&amp;gt;(_props);
    const auto &amp;amp;newScreenProps = *std::static_pointer_cast&amp;lt;const RNCSliderProps&amp;gt;(props);

        if (oldScreenProps.step != newScreenProps.step) {
        slider.step = newScreenProps.step;
    }

        // Handle only supported props here
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/4dbbd74a4ddc70cd7d23394f7e111936#file-snippet-1-javascript"&gt;snippet 1.javascript&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;&lt;em&gt;snippet &lt;a href="https://github.com/callstack/react-native-slider/blob/98d5960e4e43b2876ae9a23b99f8d1ab363d5274/package/ios/RNCSliderComponentView.mm#L144"&gt;source code&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;However, Android handles props a little bit differently. It generates setters for all of the props which need to be overwritten.&lt;/p&gt;

&lt;p&gt;The best way to tackle this problem is to override those setters with empty functions like here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// iOS only prop
@Override
public void setVertical(ReactSlider view, boolean value) {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/7c0815418741bc4d1b5493c41a78e553#file-snippet-2-javascript"&gt;snippet 2.javascript&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Union types&lt;/strong&gt;&lt;br&gt;
Typescript union types are not yet supported by Codegen, but we can get around this limitation by using a Codegen &lt;a href="https://reactnative.dev/docs/new-architecture-library-intro#codegen-helper-types"&gt;helper type&lt;/a&gt; named &lt;code&gt;WithDefault&amp;lt;&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is what this “hack” looks like in &lt;code&gt;react-native-pager-view&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;overScrollMode?: WithDefault&amp;lt;'auto' | 'always' | 'never', 'auto'&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/b520768c36361c103d987d2dacfe0481#file-snippet-3-javascript"&gt;snippet 3.javascript&lt;/a&gt; hosted with ❤ by GitHub&lt;br&gt;
If you ever get stuck, you can go through these resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;react-native&lt;/code&gt; source code (features a lot of fabric components)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/reactwg/react-native-new-architecture/discussions/6"&gt;Working Group for the New Architecture&lt;/a&gt; - features a list of already migrated libraries.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s also worth mentioning that Meta is working on &lt;a href="https://github.com/facebook/react-native/issues/34872"&gt;making Codegen support more advanced&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. Migrating deprecated APIs
&lt;/h2&gt;

&lt;p&gt;Both projects I’ve worked on haven’t used any of the deprecated APIs. However, one of the most used ones is &lt;code&gt;setNativeProps&lt;/code&gt;. It fundamentally breaks the model of the New Architecture leading to skipping all the rendering steps and desynchronising UI between React Native and what’s shown to the user. You can read more about it on &lt;a href="https://github.com/reactwg/react-native-new-architecture/discussions/77"&gt;github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you happen to use one of the APIs from &lt;a href="https://reactnative.dev/docs/new-architecture-library-intro#preparing-your-javascript-codebase-for-the-new-react-native-renderer-fabric"&gt;this list&lt;/a&gt; though, it should be pretty straightforward to just replace them. You can find helpful resources in the &lt;a href="https://github.com/reactwg/react-native-new-architecture/discussions"&gt;Working Group discussion on the New Architecture&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Implementing Codegen generated interfaces on native platforms (Android / iOS)
&lt;/h2&gt;

&lt;p&gt;This step is probably the most time consuming and it depends on the complexity of your library.&lt;/p&gt;

&lt;p&gt;Android part is easier since we are having two source sets (&lt;code&gt;newarch&lt;/code&gt; / &lt;code&gt;oldarch&lt;/code&gt;) which get loaded accordingly to a &lt;code&gt;newArchEnabled&lt;/code&gt; flag in &lt;code&gt;build.gradle&lt;/code&gt; and then a one &lt;code&gt;SharedImpl&lt;/code&gt; file which you can share between implementations.&lt;/p&gt;

&lt;p&gt;However, iOS is based on creating a new &lt;code&gt;.mm&lt;/code&gt; files which are &lt;code&gt;implementing&lt;/code&gt; Codegen generated protocols. Depending on what’s your library doing you may need to create separate implementations for new / old arch or share code between them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using Swift&lt;/strong&gt;&lt;br&gt;
Both of the libraries I’ve worked on haven’t used Swift. But, unfortunately, it’s not officially supported at the moment. The official Meta team statement is that they are “looking into it.” Codegen generates native ObjC++ files (&lt;code&gt;.mm&lt;/code&gt;) which are tricky to reference from Swift files.&lt;/p&gt;

&lt;p&gt;There is a great twitter thread from Mateusz Mędrek on his experiences.&lt;br&gt;
&lt;a href="https://twitter.com/mateusz1913/status/1574150706382229511?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1574150706382229511%7Ctwgr%5E55a5ee86f092d9174c627003f86a76763dd8cb6d%7Ctwcon%5Es1_&amp;amp;ref_url=https%3A%2F%2Fwww.callstack.com%2Fblog%2Fmigrating-a-react-native-library-to-the-new-architecture"&gt;https://twitter.com/mateusz1913/status/1574150706382229511?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1574150706382229511%7Ctwgr%5E55a5ee86f092d9174c627003f86a76763dd8cb6d%7Ctwcon%5Es1_&amp;amp;ref_url=https%3A%2F%2Fwww.callstack.com%2Fblog%2Fmigrating-a-react-native-library-to-the-new-architecture&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using Kotlin&lt;/strong&gt;&lt;br&gt;
When we were migrating react-native-pager-view I had lots of build issues which resulted from using Kotlin. Due to mixing Java with Kotlin, Codegen created files which were not included. So we have added a temporary workaround which may be useful in case you are also using Kotlin in your library. Check it out here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sourceSets {
    main {
      if (isNewArchitectureEnabled()) {
          java.srcDirs += [
            "src/fabric/java",
            "${project.buildDir}/generated/source/codegen/java"
          ]
      } else {
          java.srcDirs += ["src/paper/java"]
      }
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/4d48d0f481081b73a4d15c1d1e72caa6#file-snippet-javascript"&gt;snippet.javascript&lt;/a&gt; hosted with ❤ by GitHub&lt;br&gt;
&lt;em&gt;snippet &lt;a href="https://github.com/callstack/react-native-pager-view/blob/f931e42e2d618f5ac17d64e4cc8fc654f6ed9fef/android/build.gradle#L59"&gt;source code&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Custom component state with C++&lt;/strong&gt;&lt;br&gt;
In some use cases Codegen isn’t enough - it’s a good starting point but It wasn’t designed to cover all the edge cases. So if your native component would like to update its frames in a &lt;a href="https://reactnative.dev/architecture/render-pipeline"&gt;synchronous way&lt;/a&gt;, you will need to add custom C++ state.&lt;/p&gt;

&lt;p&gt;I haven’t added custom shadow nodes to &lt;code&gt;react-native-slider&lt;/code&gt; in C++ yet (it’s scary but it’s on my to do list 😄). We have lots of great &lt;a href="https://www.callstack.com/team"&gt;developers&lt;/a&gt; working on improving the New Architecture here at Callstack. My colleague &lt;a href="https://www.callstack.com/team/piotr-trocki"&gt;Piotr Trocki&lt;/a&gt; together with &lt;a href="https://twitter.com/cortinico"&gt;Nicola Corti&lt;/a&gt; created a &lt;a href="https://github.com/callstack/fabric-library-with-custom-cpp-example"&gt;sample repository&lt;/a&gt; which will help you set this up. Right know the guide only covers Fabric, yet there is already an &lt;a href="https://github.com/callstack/fabric-library-with-custom-cpp-example/issues/2"&gt;open issue&lt;/a&gt; to support Turbo Modules.&lt;/p&gt;

&lt;p&gt;If you are afraid of C++ you can make use of the good old bridge as it’s still being initialized. But keep in mind that one day there will be bridgeless mode added.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build times&lt;/strong&gt;&lt;br&gt;
While I was working on migration of &lt;code&gt;react-native-slider&lt;/code&gt; we were using react-native &lt;code&gt;0.69&lt;/code&gt; which had a major flaw in terms of build times. When it was time to create a fresh build without any cache, I could go and make myself a coffee ☕️ and then go for a walk. It took around 15-20 minutes. The good thing is that the community have added an &lt;code&gt;--active-arch-only&lt;/code&gt; flag which will decrease your build times even 3x. And the core team is actively working on bringing the build times down by leveraging &lt;a href="https://github.com/react-native-community/discussions-and-proposals/pull/508"&gt;prebuilt artifacts&lt;/a&gt; outside of NPM.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/o_kwasniewski/status/1585270027942502404?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1585270027942502404%7Ctwgr%5E89ce2dd0d0d74ac26d77a1ff1aea239484ef7c69%7Ctwcon%5Es1_&amp;amp;ref_url=https%3A%2F%2Fwww.callstack.com%2Fblog%2Fmigrating-a-react-native-library-to-the-new-architecture"&gt;https://twitter.com/o_kwasniewski/status/1585270027942502404?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E1585270027942502404%7Ctwgr%5E89ce2dd0d0d74ac26d77a1ff1aea239484ef7c69%7Ctwcon%5Es1_&amp;amp;ref_url=https%3A%2F%2Fwww.callstack.com%2Fblog%2Fmigrating-a-react-native-library-to-the-new-architecture&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also keep in mind that you will need a pretty good machine to play around with new architecture. I saw few comments to my tweet indicating that building app (using new architecture) took them around 30 minutes. Of course once the build is cached it will be faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Now it’s time to release a migrated library
&lt;/h2&gt;

&lt;p&gt;Every migrated library brings us closer and closer to finally enable the New Architecture in the production apps. Meta is using Fabric in their Facebook app since last year, but most of us are probably still blocked by the libraries that don’t have support for the New Architecture yet. If you want to track the status of migration for libraries, there is a &lt;a href="https://github.com/reactwg/react-native-new-architecture/discussions/6"&gt;dedicated discussion page&lt;/a&gt;. And if you are working on migrating your library, also add it there so it will be listed in the React Native Directory as a library that &lt;a href="https://reactnative.directory/?newArchitecture=true"&gt;supports the New Architecture&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EED9WPg5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tl4itw1i0v31g6tbagvu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EED9WPg5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tl4itw1i0v31g6tbagvu.png" alt="Image description" width="800" height="259"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Try React Native Slider with Fabric
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create a new app using React Native CLI: &lt;code&gt;npx react-native init NewArchApp&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add a React Native slider &lt;code&gt;yarn add react-native-slider&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[iOS] Run &lt;code&gt;RCT_NEW_ARCH_ENABLED=1 pod install&lt;/code&gt; inside ios folder&lt;/li&gt;
&lt;li&gt;[Android] Set &lt;code&gt;newArchEnabled=true&lt;/code&gt; in &lt;code&gt;gradle.properties&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the New Architecture mode, components that are not yet compatible will show a red box: &lt;code&gt;Unimplemented component: &amp;lt;ComponentName&amp;gt;&lt;/code&gt;, and you will likely notice them. In that case, please let the library maintainers know about it.&lt;/p&gt;

&lt;p&gt;Here is an example of not yet fabric ready &lt;code&gt;LottieAnimationView&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BKXaRvrR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ove1cgve16vi1bttzbc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BKXaRvrR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ove1cgve16vi1bttzbc.png" alt="Image description" width="800" height="1731"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Even though the React Native New Architecture is out there for a good while now, it’s still a challenge to do migrations, especially Fabric. The React Native core team put a good amount of work into making this effort easier. There’s a lot new documentation and up-to-date repositories on how to migrate both libraries and apps. And it’s still not enough. We keep finding the gaps in the official docs and often need to dive into the source code and commit history to figure out the rationale behind some API decisions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/cortinico"&gt;Nicola Corti&lt;/a&gt; from the core team frequently mentions at conferences and podcasts that now it is the best time for apps to migrate. That’s because now &lt;strong&gt;they have a dedicated capacity to help the community solve their app and library problems&lt;/strong&gt; in a close cooperation. They can’t promise whether they’ll have this capacity in a year from now.&lt;/p&gt;

&lt;p&gt;At Callstack, together with my fellow developers, we often took this opportunity to reach out directly to the core team members, be it around the New Architecture’s autolinking, or migrating Slider, PagerView and Bob. And they are always utterly helpful, even though not available on-demand.&lt;/p&gt;

&lt;p&gt;Although this may not be the best time for your app to adopt the New Architecture, I strongly encourage you to try. Turn on the build flag, check which components and modules are missing support. Post your problems and findings in a &lt;a href="https://github.com/reactwg/react-native-new-architecture"&gt;github discussion group&lt;/a&gt;. The New Architecture is the biggest thing that has happened to React Native since its inception. Get involved 🙂&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was originally published at &lt;a href="https://www.callstack.com/blog/migrating-a-react-native-library-to-the-new-architecture"&gt;callstack.com&lt;/a&gt; on November 3, 2022.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>newarchitecture</category>
      <category>migration</category>
    </item>
    <item>
      <title>Stripe Identity: ID Authentication Made Simple</title>
      <dc:creator>Callstack Engineers</dc:creator>
      <pubDate>Fri, 04 Nov 2022 12:00:47 +0000</pubDate>
      <link>https://dev.to/callstackengineers/stripe-identity-id-authentication-made-simple-4j7k</link>
      <guid>https://dev.to/callstackengineers/stripe-identity-id-authentication-made-simple-4j7k</guid>
      <description>&lt;p&gt;by &lt;a href="https://www.callstack.com/team/jan-jaworski"&gt;Jan Jaworski&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Stripe Identity?
&lt;/h2&gt;

&lt;p&gt;There’s no easier way to verify identities than &lt;a href="https://stripe.com/identity"&gt;Stripe Identity&lt;/a&gt;. It lets you programmatically confirm the identity of users around the globe by scanning an image of an official form of ID, so you can prevent attacks from fraudsters while minimizing friction for legitimate payments.&lt;/p&gt;

&lt;p&gt;Stripe Identity is an &lt;a href="https://www.callstack.com/open-source"&gt;open source&lt;/a&gt; React Native wrapper for the native Stripe SDKs. The idea is to compare your Face ID with images of you and your IDs by means of biometric technology. &lt;/p&gt;

&lt;p&gt;With the Stripe Identity React Native SDK, you can confidently verify the authenticity of ID documents from over 33 countries in your React Native application.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use the Stripe Identity React Native SDK
&lt;/h2&gt;

&lt;p&gt;To verify your user’s identity, you need to have a document upload sheet displayed in your application. There are few steps to do that. First of all, you have to install &lt;a href="https://github.com/stripe/stripe-identity-react-native"&gt;Stripe Identity React Native SDK&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The next step is to set up a server to create a VerificationSession, which is the programmatic representation of the verification. For security reasons, the VerificationSession API is not directly accessible from the mobile client. Instead, your server provides the SDK with an ephemeral key—a short-lived API key with restricted access to the VerificationSession API. &lt;/p&gt;

&lt;p&gt;You can think of an ephemeral key as a session authorizing the SDK to retrieve and update a specific VerificationSession object for the duration of the session. After successfully creating a VerificationSession and ephemeral key, send the VerificationSession id and ephemeral key secret to the client to show the document upload sheet. &lt;/p&gt;

&lt;p&gt;The third step is to show the “document upload” sheet to the user. With Stripe Identity React Native, you can do this in two ways - via a hook called useStripeIdentity, or a method called presentIdentityVerificationSheet. That depends on whether you want to use it in functional or class based components.&lt;/p&gt;

&lt;p&gt;You can find example code in the &lt;a href="https://github.com/stripe/stripe-identity-react-native"&gt;repository&lt;/a&gt; or &lt;a href="https://github.com/stripe/stripe-identity-react-native"&gt;integration guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started with the useStripeIdentity hook
&lt;/h2&gt;

&lt;p&gt;The easiest way to use the SDK is to import the useStripeIdentity hook directly in a functional component. You should pass the necessary information you fetched from your server directly to the hook.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react";
import { View, Button, Text, Image } from "react-native";
import { useStripeIdentity } from "@stripe/stripe-identity-react-native";

// brand logo that needs to be passed to Stripe Identity hook
import logo from "./assets/{{YOUR_BRAND_LOGO}}.png";

// simplified example of fetch function for Stripe Identity
// it can be replaced with more robust implementation that handles error handling, analytics, etc.
// other fetching libraries like Axios can be used as a replacement for native fetch()
const fetchVerificationSessionParams = async () =&amp;gt; {
 try {
   const data = await fetch(
     `${YOUR_SERVER_BASE_URL}/create-verification-session`,
     {
       method: "POST",
       headers: {
         "Content-Type": "application/json"
       }
     }
   );
   const json = await data.json();
   return json;
 } catch (e) {
   return {};
 }
 };

// options needed to make correct request to Stripe Identity
const fetchOptions = async () =&amp;gt; {
 const response = await fetchVerificationSessionParams();
 return {
   sessionId: response.id,
   ephemeralKeySecret: response.ephemeral_key_secret,
   brandLogo: Image.resolveAssetSource(logo)
 };
};

function VerifyScreen() {
 // hook provided by Stripe Identity SDK allows API consumers to get important states and values without too much work from their side.
 const { status, present, loading } = useStripeIdentity(fetchOptions);

 return (
   &amp;lt;View&amp;gt;
     &amp;lt;Button title="Verify" disabled={loading} onPress={present} /&amp;gt;
     &amp;lt;Text&amp;gt;Status: {status}&amp;lt;/Text&amp;gt;
   &amp;lt;/View&amp;gt;
 );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/3bae84b3a6a30b6ccb2b383641c158b1#file-code-snippet-1-javascript"&gt;code snippet 1.javascript&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;The hook returns 3 fields: &lt;strong&gt;status&lt;/strong&gt; (FlowCompleted, FlowCanceled, FlowFailed), &lt;strong&gt;loading&lt;/strong&gt; boolean, or &lt;strong&gt;error&lt;/strong&gt;, and a method: present. Use the &lt;strong&gt;present&lt;/strong&gt; method to display a document verification sheet. Clicking the verify button will open a native modal view.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the Stripe Identity SDK without hooks
&lt;/h2&gt;

&lt;p&gt;If you use class-based components or prefer to implement the SDK without using hooks in your RN application, you can import an async method called presentIdentityVerificationSheet and prepare your own implementation. You will pass the same parameters as with functional components. &lt;/p&gt;

&lt;p&gt;This method returns a status and an optional error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react";
import { View, Button, Text } from "react-native";
import { presentIdentityVerificationSheet } from "@stripe/stripe-identity-react-native";

const fetchVerificationSessionParams = async () =&amp;gt; {
 //  same implementation as in function component
};

const fetchOptions = async () =&amp;gt; {
 //  same implementation as in function component
};

class VerifyScreen extends React.Component {
 constructor(props) {
   super(props);
   this.state = { loading: false, status: undefined, error: undefined };
 }

 present = async () =&amp;gt; {
   // without provided hooks implementation user has to manage error and loading states manually
   this.setState({ loading: true });
   const options = await fetchOptions();
   this.setState({ loading: false });
   const { status, error } = await presentIdentityVerificationSheet(options);
   this.setState({ status, error });
 };

 render() {
   return (
     &amp;lt;View&amp;gt;
       &amp;lt;View&amp;gt;
         {this.state.loading ? (
           &amp;lt;View&amp;gt;
             &amp;lt;Text&amp;gt;Loading...&amp;lt;/Text&amp;gt;
           &amp;lt;/View&amp;gt;
         ) : (
           &amp;lt;Button title="Verify Identity" onPress={this.present} /&amp;gt;
         )}
       &amp;lt;/View&amp;gt;
       &amp;lt;Text&amp;gt;Status: {this.state.status}&amp;lt;/Text&amp;gt;
     &amp;lt;/View&amp;gt;
   );
 }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/c4a926e875fe4053fd007a6f7cc38d5b#file-code-snippet-2-javascript"&gt;code snippet 2.javascript&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;h2&gt;
  
  
  Verifying results
&lt;/h2&gt;

&lt;p&gt;Based on the status (FlowCompleted, FlowCancelled, FlowFails), you'll need to handle these outcomes in your application. Please refer to the &lt;a href="https://stripe.com/docs/identity/handle-verification-outcomes"&gt;official documentation&lt;/a&gt; to read more about setting up a webhook flow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error handling
&lt;/h2&gt;

&lt;p&gt;When implementing such a critical feature for your app, it is important to correctly implement error handling and provide users with clear information about the source of the issue and how they should proceed. If the error is on their side, your application should tell the user what to do to fix the problem. If the problem is due to code or server issues, there should be a clear message saying it.&lt;/p&gt;

&lt;p&gt;Stripe Identity SDK provides a number of statuses and messages that can be used to create robust error handling implementation in your application.&lt;/p&gt;

&lt;p&gt;Both &lt;code&gt;useStripeIdentity&lt;/code&gt; and &lt;code&gt;presentIdentityVerificationSheet&lt;/code&gt; provide you with information about the errors.&lt;/p&gt;

&lt;h2&gt;
  
  
  TypeScript support
&lt;/h2&gt;

&lt;p&gt;Stripe Identity React Native SDK provides TypeScript support - it’s actually written in TypeScript. If you use it in your RN project, you can also use the types that SDK provided - StripeError and IdentityVerificationSheetStatus. Both can be useful while using the method presentIdentityVerificationSheet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stripe Identity features
&lt;/h2&gt;

&lt;p&gt;Stripe Identity SDK offers a number of features that allow you to quickly introduce identity verification in your app. It ensures a secure and law-compliant implementation that should cover most of you and your users’ needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simplified security
&lt;/h2&gt;

&lt;p&gt;It’s simple for you to securely collect your user’s personally identifiable information (PII) such as identity document images. Sensitive PII data is sent directly to Stripe Identity instead of passing through your server. More information in the &lt;a href="https://stripe.com/docs/security"&gt;integration security guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automatic document capture
&lt;/h2&gt;

&lt;p&gt;We automatically capture images of the front and back of government-issued photo ID to ensure a clear and readable image.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prebuilt UI
&lt;/h2&gt;

&lt;p&gt;We provide &lt;a href="https://stripe.com/docs/security"&gt;IdentityVerificationSheet&lt;/a&gt;, a prebuilt UI that combines all the steps required to collect ID documents, selfies, and ID numbers into a single sheet that displays on top of your app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automated verification
&lt;/h2&gt;

&lt;p&gt;Stripe Identity's automated verification technology looks for patterns to help determine if an ID document is real or fake and uses distinctive physiological characteristics of faces to match your users' selfies to photos on their ID document.&lt;/p&gt;

&lt;p&gt;Collected identity information is checked against a global set of databases to confirm that it exists. Learn more about the &lt;a href="https://stripe.com/docs/identity/verification-checks"&gt;verification checks&lt;/a&gt; supported by Stripe Identity, &lt;a href="https://stripe.com/docs/identity/verification-checks"&gt;accessing verification results&lt;/a&gt;, or integration guide on &lt;a href="https://stripe.com/docs/identity/access-verification-results"&gt;handling verification outcomes&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Stripe Identity was born to make the ID verification process faster and more efficient. Thanks to the technology used, online businesses can easily confirm their users’ identities. It’s a great convenience and, most importantly, a viable safety measure that should be widely adopted.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was originally published at &lt;a href="https://www.callstack.com/blog/stripe-identity-id-authentication-made-simple"&gt;callstack.com&lt;/a&gt; on October 28, 2022.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>security</category>
      <category>identitycheck</category>
    </item>
    <item>
      <title>Setting up React Native Monorepo with Yarn Workspaces</title>
      <dc:creator>Callstack Engineers</dc:creator>
      <pubDate>Fri, 14 Oct 2022 19:10:04 +0000</pubDate>
      <link>https://dev.to/callstackengineers/setting-up-react-native-monorepo-with-yarn-workspaces-4kj0</link>
      <guid>https://dev.to/callstackengineers/setting-up-react-native-monorepo-with-yarn-workspaces-4kj0</guid>
      <description>&lt;p&gt;by Oskar Kwaśniewski&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a monorepo?
&lt;/h2&gt;

&lt;p&gt;A monorepo is a single repository that holds a multitude of projects with all their code and assets. While the projects can be related, they can be used independently by different teams. &lt;/p&gt;

&lt;p&gt;Working with monorepos is very useful, especially when developing big and complex applications like &lt;a href="https://www.callstack.com/blog/why-have-a-super-app"&gt;super apps&lt;/a&gt;. Monorepos enable sharing the logic between a web app and a mobile app, for example.&lt;/p&gt;

&lt;p&gt;In this article, we’re going to set up a basic structure for a monorepo in React Native.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use monorepo in React Native?
&lt;/h2&gt;

&lt;p&gt;Thanks to react-native-web we can share every component so there’s no need to duplicate the code many times. This means easier dependency management, shorter CI times, and better collaboration between teams since the code can be shared.&lt;/p&gt;

&lt;p&gt;The main advantage though is the possibility of sharing packages between React and React Native. Most of the time we decide to share only business logic, but thanks to React Native Web, we can also share some of the UI components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up Yarn workspaces
&lt;/h2&gt;

&lt;p&gt;While setting up a monorepo, we have two options: we can either hoist the packages to the root level or prevent them from hoisting. Yarn workspaces have an option named nohoist which allows us to specify packages that aren’t hoisted. It depends on your use case but most of the time &lt;strong&gt;it’s better to hoist packages to the root level&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Alternatively, you can use &lt;a href="https://docs.npmjs.com/cli/v7/using-npm/workspaces"&gt;npm workspaces&lt;/a&gt;, it &lt;em&gt;should&lt;/em&gt; work the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it’s better to avoid using nohoist
&lt;/h2&gt;

&lt;p&gt;Preventing packages from hoisting takes back the main advantage of monorepos which is sharing &lt;code&gt;node_modules&lt;/code&gt; between repositories. When nohoist option is turned on, most of the time packages are duplicated inside the root level &lt;code&gt;node_modules&lt;/code&gt; and inside the project level &lt;code&gt;node_modules&lt;/code&gt;. Downloading packages multiple times can lead to longer CI/CD runs and higher costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rearranging the project structure
&lt;/h2&gt;

&lt;p&gt;In order to set up yarn workspaces, we need to restructure our project to suit the structure below. Projects need to be divided into separate folders and we should have root level &lt;code&gt;package.json&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;your-project
    packages
        web // &amp;lt;- React app
        mobile // &amp;lt;- React Native app
        shared // &amp;lt;- Shared (includes files shared between mobile/web)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/153f4e4e15791065fd01dd57cb426730#file-plain1-txt"&gt;plain1.txt&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;Next, you should create a package.json file in the root directory of our project with this command: &lt;code&gt;$ yarn init -y&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;It should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "private": "true",
  "name": "example-app",
  "version": "1.0.0",
  "workspaces": [
    "packages/*"
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/00a07fe6d69f1d9fa9270db86bc3a2a4#file-codesnippet1-json"&gt;codesnippet1.json&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;Note that private: true is required because workspaces are not meant to be published.&lt;/p&gt;

&lt;p&gt;In the workspaces section, we define a &lt;strong&gt;work tree&lt;/strong&gt;. We can pass there an &lt;strong&gt;array of glob patterns that should be used to locate the workspaces&lt;/strong&gt;. So in the example above, every folder inside packages is defined as a workspace.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a React Native project
&lt;/h2&gt;

&lt;p&gt;Use command below to create a React Native project inside the &lt;code&gt;packages&lt;/code&gt; folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npx react-native init ExampleApp --directory mobile --template react-native-template-typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/f666e8c6ada815b30444b70e6e1e4e19#file-plain2-txt"&gt;plain2.txt&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;In order for our app to work in a monorepo structure, we need to make sure that config files are pointing to the root level &lt;code&gt;node_modules&lt;/code&gt; due to package hoisting.&lt;/p&gt;

&lt;h2&gt;
  
  
  iOS setup
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Change paths at the top of your Podfile
- require_relative '../node_modules/react-native/scripts/react_native_pods'
- require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
+ require_relative '../../../node_modules/react-native/scripts/react_native_pods'
+ require_relative '../../../node_modules/@react-native-community/cli-platform-ios/native_modules'

target 'ExampleApp' do
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/b6f07259a08e8af8f4b678266c724fd4#file-path1-diff"&gt;path1.diff&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;Regenerate Pods, by entering the command below in the packages/mobile folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd ios &amp;amp;&amp;amp; pod install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/dc54172d5b9e2fb78e96b8c0ac95723c#file-plain3-txt"&gt;plain3.txt&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;Next open Xcode and inside Project settings &amp;gt; Build Phases open “Bundle React Native code and images”&lt;/p&gt;

&lt;p&gt;Change the path of the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;set -e

- WITH_ENVIRONMENT="../../node_modules/react-native/scripts/xcode/with-environment.sh"
- REACT_NATIVE_XCODE="../../node_modules/react-native/scripts/react-native-xcode.sh"
+ WITH_ENVIRONMENT="../../../node_modules/react-native/scripts/xcode/with-environment.sh"
+ REACT_NATIVE_XCODE="../../../node_modules/react-native/scripts/react-native-xcode.sh"

/bin/sh -c "$WITH_ENVIRONMENT $REACT_NATIVE_XCODE" 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/47fa581379143d26ffb8b941d97f6969#file-path2-diff"&gt;path2.diff&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;It should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EUSiX-rS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i5uy6fqsg2hbm1qom523.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EUSiX-rS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i5uy6fqsg2hbm1qom523.png" alt="Image description" width="880" height="545"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Android setup
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;React Native ≥ 0.71&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Uncomment the line with &lt;code&gt;reactNativeDir&lt;/code&gt; and point it to root &lt;code&gt;node_modules&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// packages/mobile/android/app/build.gradle

react { 
+  hermesCommand = "../../node_modules/react-native/sdks/hermesc/%OS-BIN%/hermesc"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/959430f8f3dfb5f0ada39058e732c16e#file-android-1-diff"&gt;android 1.diff&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;In top-level &lt;code&gt;build.gradle&lt;/code&gt; add this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;allprojects {
    project.pluginManager.withPlugin("com.facebook.react") {
        react {
            reactNativeDir = rootProject.file("../../../node_modules/react-native/")
            codegenDir = rootProject.file("../../../node_modules/react-native-codegen/")
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/394a81925dab92be914fdfedac3d6bf0#file-android-2-shell"&gt;android 2.shell&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;and inside: &lt;code&gt;packages/mobile/android/settings.gradle&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+ apply from: file("../../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
+ includeBuild('../../../node_modules/react-native-gradle-plugin')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/31ebc8fe1081b3d18d6dda7c5460f946#file-android-3-diff"&gt;android 3.diff&lt;/a&gt; hosted with ❤ by GitHub&lt;br&gt;
‍&lt;br&gt;
&lt;strong&gt;React Native ≤ 0.71&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Fix paths inside &lt;code&gt;packages/mobile/android/build.gradle&lt;/code&gt;&lt;br&gt;
Change url of the React Native Android binaries, and Android JSC in the &lt;code&gt;allprojects&lt;/code&gt; section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;allprojects {
    repositories {
        maven {
            // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
-            url("$rootDir/../node_modules/react-native/android")
+            url("$rootDir../../../../node_modules/react-native/android")
        }
        maven {
            // Android JSC is installed from npm
-            url("$rootDir/../node_modules/jsc-android/dist")
+            url("$rootDir../../../../node_modules/jsc-android/dist")
        }
                ...
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/0f6d4ce0be60e41092ed684831768865#file-code-snippet2-diff"&gt;code snippet2.diff&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;Fix &lt;code&gt;packages/mobile/android/settings.gradle&lt;/code&gt;&lt;br&gt;
Here we also need to change paths to the root &lt;code&gt;node_modules&lt;/code&gt; folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rootProject.name = 'example-app'
- apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
- includeBuild('../node_modules/react-native-gradle-plugin')
+ apply from: file("../../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
+ includeBuild('../../../node_modules/react-native-gradle-plugin')
include ':app'
if (settings.hasProperty("newArchEnabled") &amp;amp;&amp;amp; settings.newArchEnabled == "true") {
    include(":ReactAndroid")
-   project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid')
+   project(":ReactAndroid").projectDir = file('../../../node_modules/react-native/ReactAndroid')
    include(":ReactAndroid:hermes-engine")
-   project(":ReactAndroid:hermes-engine").projectDir = file('../node_modules/react-native/ReactAndroid/hermes-engine')
+   project(":ReactAndroid:hermes-engine").projectDir = file('../../../node_modules/react-native/ReactAndroid/hermes-engine')
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/912dc87a0fcaf5f3b3268ce802aea09d#file-path3-diff"&gt;path3.diff&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;Next go to &lt;code&gt;packages/mobile/android/app/build.gradle&lt;/code&gt;&lt;br&gt;
Inside the &lt;code&gt;project.ext.react&lt;/code&gt; we need to add property &lt;code&gt;cliPath&lt;/code&gt; so it will override the default location of the cli.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;project.ext.react = [
+    cliPath: "../../../../node_modules/react-native/cli.js",
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/a138c380342986006c11453c81fa450a#file-plain4-txt"&gt;plain4.txt&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;In the same file, change this line: &lt;code&gt;apply from: "../../node_modules/react-native/react.gradle"&lt;/code&gt; to point to root level &lt;code&gt;node_modules&lt;/code&gt; as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- apply from: "../../node_modules/react-native/react.gradle"
+ apply from: "../../../../node_modules/react-native/react.gradle"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/869f2e7ac507c6dbfb753454eccf2cc7#file-path4-diff"&gt;path4.diff&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;And also change: inside &lt;code&gt;packages/mobile/android/app/build.gradle&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
+ apply from: file("../../../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/c49912a600849eaaaa91fb3a0c488707#file-path5-diff"&gt;path5.diff&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;If you are using or planning to use the new architecture, we also need to change a few lines in the &lt;code&gt;isNewArchitectureEnabled()&lt;/code&gt; if statement*&lt;em&gt;.&lt;/em&gt;*&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (isNewArchitectureEnabled()) {
            // We configure the NDK build only if you decide to opt-in for the New Architecture.
            externalNativeBuild {
                ndkBuild {
                    arguments "APP_PLATFORM=android-21",
                        "APP_STL=c++_shared",
                        "NDK_TOOLCHAIN_VERSION=clang",
                        "GENERATED_SRC_DIR=$buildDir/generated/source",
                        "PROJECT_BUILD_DIR=$buildDir",
-                       "REACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
-                       "REACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build",
-                       "NODE_MODULES_DIR=$rootDir/../node_modules"
+                       "REACT_ANDROID_DIR=../../node_modules/react-native/ReactAndroid",
+                       "REACT_ANDROID_BUILD_DIR=../../node_modules/react-native/ReactAndroid/build",
+                       "NODE_MODULES_DIR=../../node_modules"
                    cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
                    cppFlags "-std=c++17"
                    // Make sure this target name is the same you specify inside the
                    // src/main/jni/Android.mk file for the `LOCAL_MODULE` variable.
                    targets "okwasniewskionboarding_appmodules"
                }
            }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/8f6a7f101afe659c4b4d74f7d8f26531#file-code-snippet-3-diff"&gt;code snippet 3.diff&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Metro
&lt;/h2&gt;

&lt;p&gt;We’re almost done with setting up the project. The last thing in the React Native app is to add &lt;code&gt;watchFolders&lt;/code&gt; so metro knows where the linked &lt;code&gt;node_modules&lt;/code&gt; are. The shared modules are symlinked by yarn, and since &lt;a href="https://github.com/facebook/metro/issues/1"&gt;metro doesn’t follow symlinks&lt;/a&gt; we need to explicitly say it where the linked &lt;code&gt;node_modules&lt;/code&gt; are.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const path = require("path");

// packages/mobile/metro.config.js
module.exports = {
  watchFolders: [
    path.resolve(__dirname, '../../node_modules')
  ],
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/36f0d1e17290db96872b9ce62eed73fa#file-code-snippet4-javascript"&gt;code snippet4.javascript&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a shared package
&lt;/h2&gt;

&lt;p&gt;To keep it simple, we’re going to share only one function across React Native and React.&lt;/p&gt;

&lt;p&gt;Inside the &lt;code&gt;packages/shared&lt;/code&gt;, create a new &lt;code&gt;package.json&lt;/code&gt; file with the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ yarn init -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/7324da94e7408a181f49567fc11e7b14#file-code-snippet5-javascript"&gt;code snippet5.javascript&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;The shared library is in typescript, so we need to set up a build step with the typescript compiler (tsc).&lt;/p&gt;

&lt;p&gt;The build step uses &lt;code&gt;rimraf&lt;/code&gt; which is a small utility for node that allows us to remove a folder, and then build the app with tsc.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;postinstall&lt;/code&gt; indicates that our shared dependency will build automatically after installing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "@example-app/shared",
  "version": "1.0.0",
  "main": "dist/index.js",
  "scripts": {
    "build": "rimraf dist &amp;amp;&amp;amp; tsc",
    "postinstall": "yarn build",
        "watch": "tsc --watch"
  },
    "dependencies": {
        "react-native": "0.69.1",
        "react": "18.0.0"
    },
    "devDependencies": {
        "rimraf": "^3.0.2",
        "typescript": "^4.4.4"
    },
  "keywords": [],
  "author": "",
  "license": "ISC"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/e801f1937a8a0fd1bb88d717de1685ff#file-code-snippet6-json"&gt;code snippet6.json&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;Note: The package name is really important, because it will indicate from where we will import our module.&lt;/p&gt;

&lt;p&gt;It’s also important to add all packages and keep the &lt;strong&gt;exact same version&lt;/strong&gt; used in a shared project and target projects.&lt;/p&gt;

&lt;p&gt;Next we need to configure &lt;code&gt;tsconfig.json&lt;/code&gt; where we can define our build settings.&lt;/p&gt;

&lt;p&gt;Here is an example config file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// packages/shared/tsconfig.json
{
    "compilerOptions": {
      "target": "es6",
      "lib": ["dom", "dom.iterable", "esnext"],
      "skipLibCheck": true,
      "esModuleInterop": true,
      "allowSyntheticDefaultImports": true,
      "strict": true,
      "forceConsistentCasingInFileNames": true,
      "module": "commonjs",
      "outDir": "dist", // &amp;lt;- Directory of generated output
      "moduleResolution": "node",
      "resolveJsonModule": true,
      "experimentalDecorators": true,
      "strictPropertyInitialization": false,
      "declaration": true,
      "jsx": "react"
    },
  } 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/8d9d72255b264de2fe5982e6875b1ee5#file-code-snippet7-json"&gt;code snippet7.json&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;Next, let’s create an &lt;code&gt;index.ts&lt;/code&gt; file inside the &lt;code&gt;packages/shared&lt;/code&gt; folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const add = (a: number, b: number) =&amp;gt; {
    return a + b;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/623e6fbe1b8241e730478b6c0b24585d#file-code-snippet8-javascript"&gt;code snippet8.javascript&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;Run this command to build the package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ yarn build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/318d2e7c05bbe7576468a600d3a08355#file-code-snippet9-javascript"&gt;code snippet9.javascript&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;Next, we need to add this package as a dependency in our react native project. So inside &lt;code&gt;packages/mobile/package.json&lt;/code&gt; add &lt;code&gt;@example-app/shared&lt;/code&gt; as a dependency.&lt;/p&gt;

&lt;p&gt;Note that the version of the package must match the version specified inside packages/shared/package.json. Previously we defined that @example-app/shared version is 1.0.0.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// packages/mobile/package.json

"dependencies": {
    "@example-app/shared": "1.0.0",
    ...
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/854fa05f5f544019f109a0d5b691fd76#file-code-snippet10-json"&gt;code snippet10.json&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;And also inside the metro.config.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// packages/mobile/metro.config.js

module.exports = {
  watchFolders: [
    path.resolve(__dirname, '../../node_modules'),
+   path.resolve(__dirname, '../../node_modules/@example-app/shared'),
  ],
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/78f3941f89f05312b9cfcca628b22e86#file-code-snippet11-javascript"&gt;code snippet11.javascript&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;Now, run this command in the root directory, so yarn will set up symlinks for your shared package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ yarn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/f6872dcef8424f3e30326430a86caf8b#file-code-snippet12-javascript"&gt;code snippet12.javascript&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;Right now we should be able to import the add function inside React Native app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import {Text, TouchableOpacity, View} from 'react-native';
import {add} from '@example-app/shared';


const App = () =&amp;gt; {
  return (
    &amp;lt;View&amp;gt;
      &amp;lt;TouchableOpacity
        accessibilityRole="button"
        onPress={() =&amp;gt; {
          console.log(add(1, 2));
        }}&amp;gt;
        &amp;lt;Text&amp;gt;Run Add function&amp;lt;/Text&amp;gt;
      &amp;lt;/TouchableOpacity&amp;gt;
    &amp;lt;/View&amp;gt;
  );
};

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/5bc1162031483af83707c89aa8854e74#file-code-snippet13-javascript"&gt;code snippet13.javascript&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a React project
&lt;/h2&gt;

&lt;p&gt;In order to set up a React project, execute the command below inside &lt;code&gt;packages/web&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npx create-react-app . ExampleApp --template typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/288c2cb2f518d623ee6f41a75fc542a5#file-code-snippet14-javascript"&gt;code snippet14.javascript&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;Add &lt;code&gt;@example-app/shared&lt;/code&gt; dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// packages/web/package.json
"dependencies": {
    "@example-app/shared": "1.0.0",
    ...
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/59500de36f12feadf226b26473b2433e#file-code-snippet15-json"&gt;code snippet15.json&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;And we can import and use the shared package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import {add} from '@example-app/shared';


const App = () =&amp;gt; {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; console.log(add(1,2))}&amp;gt;Run add function&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
};

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/68fa870f8ea07910622941afe92555a1#file-code-snippet16-javascript"&gt;code snippet16.javascript&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;h2&gt;
  
  
  Sharing UI components with React Native Web
&lt;/h2&gt;

&lt;p&gt;In order to share UI components, we need React Native Web which provides a compatibility layer between React DOM and React Native.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation steps
&lt;/h2&gt;

&lt;p&gt;Install react-native-web:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ yarn add react-native-web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/72f809a51365c0b37ded819c5690e1cf#file-code-snippet17-txt"&gt;code snippet17.txt&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;Install &lt;code&gt;babel-plugin-react-native-web&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ yarn add -D babel-plugin-react-native-web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/7cdc04d0036a0a9d4768a7fef7cda4fa#file-code-snippet18-txt"&gt;code snippet18.txt&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;h2&gt;
  
  
  Modify shared package to export React Native component
&lt;/h2&gt;

&lt;p&gt;First inside &lt;code&gt;packages/shared&lt;/code&gt;, create a new file called &lt;code&gt;TestComponent.tsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Text, View } from "react-native";
import React from "react";

const TestComponent = () =&amp;gt; {
  return (
    &amp;lt;View&amp;gt;
      &amp;lt;Text&amp;gt;TestComponent&amp;lt;/Text&amp;gt;
    &amp;lt;/View&amp;gt;
  );
};

export default TestComponent;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/da59241be3b409632424ee47865fe3d6#file-code-snippet-19-javascript"&gt;code snippet 19.javascript&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;Next export it from the &lt;code&gt;index.ts file&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const add = (a: number, b: number) =&amp;gt; {
    return a + b;
}

export { default as TestComponent } from './TestComponent.tsx'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/bb1004a508e5d8ec8f671c27e15a66fe#file-code-snippet20-javascript"&gt;code snippet20.javascript&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;Rebuild the shared package inside &lt;code&gt;packages/shared&lt;/code&gt; folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ yarn build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/f3f267e8708d9a0ef93a75230228b41a#file-code-snippet21-txt"&gt;code snippet21.txt&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;And now we should be able to use &lt;code&gt;TestComponent&lt;/code&gt; inside a React app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react';
import {add, TestComponent} from '@example-app/shared';


const App = () =&amp;gt; {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;button onPress={() =&amp;gt; console.log(add(1,2))}&amp;gt;Run add function&amp;lt;/button&amp;gt;
            &amp;lt;TestComponent/&amp;gt; // &amp;lt;- React Native component inside React app! 
    &amp;lt;/div&amp;gt;
  );
};

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/21edfb919df3d7e480d2ff919aa555b7#file-code-snippet22-javascript"&gt;code snippet22.javascript&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;h2&gt;
  
  
  To sum up
&lt;/h2&gt;

&lt;p&gt;Setting up a monorepo can be tricky, but it pays off in the long run! You can easily share all of your code and assets between React and React Native.&lt;/p&gt;

&lt;p&gt;Using a monorepo is growing in popularity - there is even an open proposal to &lt;a href="https://github.com/react-native-community/discussions-and-proposals/pull/480"&gt;migrate react-native repository to monorepo&lt;/a&gt;. Find out more about &lt;a href="https://github.com/okwasniewski/react-native-monorepo"&gt;React Native monorepo&lt;/a&gt; on github.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was originally published at &lt;a href="https://www.callstack.com/blog/setting-up-react-native-monorepo-with-yarn-workspaces"&gt;callstack.com&lt;/a&gt; on October 11, 2022.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>appdevelopment</category>
      <category>monorepo</category>
      <category>guide</category>
    </item>
    <item>
      <title>A Comprehensive Guide to Mock Service Worker (MSW)</title>
      <dc:creator>Callstack Engineers</dc:creator>
      <pubDate>Thu, 13 Oct 2022 16:57:33 +0000</pubDate>
      <link>https://dev.to/callstackengineers/a-comprehensive-guide-to-mock-service-worker-msw-1ng9</link>
      <guid>https://dev.to/callstackengineers/a-comprehensive-guide-to-mock-service-worker-msw-1ng9</guid>
      <description>&lt;p&gt;by &lt;a href="https://www.callstack.com/team/aleksandra-desmurs-linczewska"&gt;Aleksandra Desmurs-Linczewska&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://mswjs.io/"&gt;Mock Service Worker&lt;/a&gt; is an API mocking tool that lets you mock by intercepting requests on the network level. You can reuse the same mock definition for testing, development, and debugging. &lt;/p&gt;

&lt;p&gt;MSW is delightful to adopt. Plus, it makes testing components with network requests a pleasure. &lt;/p&gt;

&lt;p&gt;In this article, I’d like to share some best practices for working with MSW for basic and more advanced problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use a Mock Service Worker?
&lt;/h2&gt;

&lt;p&gt;Has this ever happened to you?&lt;/p&gt;

&lt;p&gt;You’ve finally gotten the green light to spend some writing tests! &lt;/p&gt;

&lt;p&gt;This sprint is calm, but you remembered all too clearly that disastrous release a few weeks ago. The entire team had to drop everything and fix bugs. &lt;/p&gt;

&lt;p&gt;Your repo has around 20% test coverage, and everyone agrees that it’s too little, but there’s never enough time to write tests. You write your features, get an LGTM on the PR, and move on. &lt;/p&gt;

&lt;p&gt;But this release will be different! &lt;/p&gt;

&lt;p&gt;You have a dedicated task, a couple of story points, and a jug of coffee to get this done right. You know the feature you’re about to test very well; you wrote most of it. You set out to mock the component and pass some props. &lt;/p&gt;

&lt;p&gt;The tests fail. &lt;/p&gt;

&lt;p&gt;No worries, that was only the first try, my friend! You re-check what needs testing, add some missing mocks, and maybe throw a &lt;code&gt;jest.spyOn&lt;/code&gt; in there. You’re so proud of your accomplishment!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;yarn test&lt;/code&gt; – another fail.&lt;/p&gt;

&lt;p&gt;You dig deeper and realize your component depends on a network request returning some data. &lt;/p&gt;

&lt;p&gt;Ok, don’t panic.&lt;/p&gt;

&lt;p&gt;Let’s see how other tests in the codebase manage this. You find tests mocking axios, other ones' mock fetch, and wait; there are also some global files mocking resolved values and network errors?&lt;/p&gt;

&lt;p&gt;You sweat a little, add many lines of code to your test, and ponder briefly if all of them are necessary. You notice tests unrelated to your changes started failing! You start feeling like the people in the first half of any infomercial.&lt;/p&gt;

&lt;p&gt;…and you probably think: there has to be a better way! That’s when &lt;strong&gt;Mock Service Worker comes in handy&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The basic guide to Mock Service Worker (MSW)
&lt;/h2&gt;

&lt;p&gt;Mock Service Worker intercepts real network requests that your tests make. &lt;/p&gt;

&lt;p&gt;The components in your tests think they are talking with the real API, which means you can &lt;strong&gt;test their &lt;em&gt;real&lt;/em&gt; functionality&lt;/strong&gt; (as opposed to testing contained, mock functionality). If you don’t feel convinced about this approach just yet, I invite you to read Kent C. Dodd’s excellent blog post: &lt;a href="https://kentcdodds.com/blog/stop-mocking-fetch"&gt;Stop Mocking Fetch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s see this magical library in action. As with any new dependency, you need to &lt;strong&gt;start by adding it to your project&lt;/strong&gt;: &lt;code&gt;npm install msw --save-dev or yarn add msw --dev&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once the installation finishes, you will have to &lt;strong&gt;define your request handlers&lt;/strong&gt;. &lt;a href="https://mswjs.io/docs/getting-started/mocks"&gt;MSW documentation&lt;/a&gt; suggests creating them in a file called &lt;code&gt;mocks/handlers.js&lt;/code&gt;. Depending on your project, you can create REST or GraphQL handlers. MSW request handlers aim to &lt;strong&gt;hold instructions for specific API endpoints&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let’s take a look at an example REST request handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// src/mocks/handlers.js
import { rest } from "msw";

export const handlers = [
  // Handles a POST request
  rest.post("https://fancy-app.com/postToThisEndpoint", (req, res, ctx) =&amp;gt; {
    return res(
      // Respond with a 200 status code
      ctx.status(200)
    );
  }),

  // Handles a GET request
  rest.get("https://fancy-app.com/getSomeData", (req, res, ctx) =&amp;gt; {
    return res(
      ctx.status(200),
      ctx.json({
        data: "fancy data string",
      })
    );
  }),
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/marta-pinkowska/2441ce919c1053770e0d4cad48cc779a#file-msw-test-tsx"&gt;msw.test.tsx&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;We start by importing the rest function from MSW, then create an array of API endpoints we want to handle. &lt;/p&gt;

&lt;p&gt;We can add anything we would like to this array. We can mock an &lt;strong&gt;error response&lt;/strong&gt;; we can mock &lt;strong&gt;correct or faulty data objects&lt;/strong&gt;. Remember to use absolute request URLs since we will use those request handlers in a NodeJS environment.&lt;/p&gt;

&lt;p&gt;The only caveat here is that if you add multiple handlers for one API endpoint, the last one in the array will be the only one that’s actually used. But more on that later.&lt;/p&gt;

&lt;p&gt;Once you have a few handlers ready, it is time to let your test suite know about them. We will need to &lt;strong&gt;set up a request mocking server and run it with our tests&lt;/strong&gt;. This may sound scary, but don’t worry; the server setup file is three lines long. &lt;/p&gt;

&lt;p&gt;Let’s create a new file called &lt;code&gt;server.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// src/mocks/server.js
import { setupServer } from 'msw/node'
import { handlers } from './handlers'

// This configures a request mocking server with the given request handlers.
export const server = setupServer(...handlers)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/marta-pinkowska/cdd96667b9f2071c4f18a6545c9537fe#file-msw-test-2-tsx"&gt;msw.test.2.tsx&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;We have to import the &lt;code&gt;setupServer&lt;/code&gt; function from &lt;code&gt;msw/node&lt;/code&gt; and pass the previously created request handlers to that function.&lt;/p&gt;

&lt;p&gt;I don’t know about you, but this is the simplest mock server setup I have ever seen!&lt;/p&gt;

&lt;p&gt;The very last step is running the mock server when you run your tests. &lt;/p&gt;

&lt;p&gt;This step depends heavily on your project setup. There are various ways to set up and configure Jest, and this blog post will not try to cover all of them.&lt;/p&gt;

&lt;p&gt;Instead, I’ll talk about the setup I’ve seen the most often: using a dedicated &lt;code&gt;setupTests.js&lt;/code&gt; file, which is called through Jest’s &lt;a href="https://jestjs.io/docs/configuration"&gt;setupFilesAfterEv&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If that’s the case in your project, congratulations! You only need to add the following lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// src/setupTests.js
import { server } from './mocks/server.js'
// Establish API mocking before all tests.
beforeAll(() =&amp;gt; server.listen())

// Reset any request handlers that we may add during the tests,
// so they don't affect other tests.
afterEach(() =&amp;gt; server.resetHandlers())

// Clean up after the tests are finished.
afterAll(() =&amp;gt; server.close())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/marta-pinkowska/81673bda4122af5fe207230af46dd2ad#file-msw-test-2-tsx"&gt;msw.test.2.tsx&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;If you prefer to test MSW quickly in a single test file, you can do so as well. &lt;/p&gt;

&lt;p&gt;It is possible to &lt;a href="https://mswjs.io/docs/getting-started/integrate/node#direct-usage"&gt;use the mock server directly&lt;/a&gt; anywhere you would like. This means you can skip all the steps above (except for the installation, let’s not get carried away!) and write something like this in your test file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// __tests__/FancyPage.test.js
import { setupServer } from "msw/node";
import { FancyComponentWithAPICall } from "../FancyComponentWithAPICall";

const server = setupServer(
  rest.get("https://fancy-app.com/getSomeData", (req, res, ctx) =&amp;gt; {
    return res(ctx.json({ data: "return this string" }));
  })
);

describe("&amp;lt;FancyComponentWithAPICall /&amp;gt;", () =&amp;gt; {
  beforeAll(() =&amp;gt; server.listen());
  afterAll(() =&amp;gt; server.close());
  test("displays data from backend", async () =&amp;gt; {
    // Render components, perform requests, receive mocked responses.
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/marta-pinkowska/5c6abaeb422dc7b6dbd69004068a6aa2#file-msw-test-4-tsx"&gt;msw.test.4.tsx&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;This has all been fun and games so far, don’t you think? &lt;/p&gt;

&lt;p&gt;Going through the setup takes less than an hour. Honestly, going through the &lt;a href="https://mswjs.io/docs/getting-started/install"&gt;official MSW documentation&lt;/a&gt; takes less than an hour! &lt;/p&gt;

&lt;p&gt;If you’re working on a project that’s not too big, you can stop reading now, pat yourself on the back, and look at all those green check marks on your tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  The advanced guide to Mock Service Worker
&lt;/h2&gt;

&lt;p&gt;If you are working on a big application, maybe a robust dashboard, or an e-commerce website, you realize the basic setup presented above won’t cut it.&lt;/p&gt;

&lt;p&gt;The handlers array will soon become a 10-thousand line mess. People may add mock servers in random tests, making debugging errors difficult. &lt;/p&gt;

&lt;p&gt;My team and I have faced those issues, and here’s how we decided to tackle them.&lt;/p&gt;

&lt;p&gt;As stated above, the biggest issue in a big app using MSW is the &lt;strong&gt;handlers' files becoming unreadable&lt;/strong&gt;. We tackled this issue by dividing the &lt;strong&gt;handlers’ files into separate, feature-related files&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Now, instead of a single, long &lt;code&gt;handlers.js&lt;/code&gt;, we had something in the shape of the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src
│
└───tools
|   └───jest
│   │   commonMswHandlers.js
│   │   server.js 
|   |   setupTests.js
│
└───featureA
│   │   FeatureA.js
|   |
|   └───__tests__
│       │   FeatureA.test.js
│   │
│   └───msw
│       │   mswHandlers.js
│   
└───featureB
│   │   FeatureB.js
|   |
|   └───__tests__
│       │   FeatureB.test.js
│   │
│   └───msw
│       │   mswHandlers.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/marta-pinkowska/749641d0b87b15cf6fdb994770ff6fee#file-msw-test-5-tsx"&gt;msw-test.5.tsx&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;A few API endpoints which were commonly needed for the tests and did not clearly fit any feature were left in the &lt;code&gt;commonMswHandlers.js&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Once we’ve effectively sliced the &lt;code&gt;handlers&lt;/code&gt; array, we started wondering how these specific request handlers should be consumed. As we saw above, we could let the test authors import &lt;code&gt;setupServer&lt;/code&gt; with specific handlers directly in the test files.&lt;/p&gt;

&lt;p&gt;However, this quickly became quite verbose. We decided to create helper functions in our &lt;code&gt;mswHandlers.js&lt;/code&gt; files. An example file would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// src/FancyHomepageFeature/msw/mswHandlers.js

import { rest } from 'msw';
// import the server created for the entire test suite
// this mock server includes commonMswHandlers
import { server } from '../tools/jest/server';

const homeHandlers = [
  rest.get('https://fancy-app.com/homepage-data', (req, res, ctx) =&amp;gt; {
    return res(
      ctx.json({
        contents: [
          {
            banner: 'Fancy Banner'
          },
        ],
      })
    );
  }),
];

export const setupHomeHandlers = () =&amp;gt; {
  server.use(...homeHandlers);
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/marta-pinkowska/f8bd761b4db21f1248423bdbfc60b4c0#file-msw-test-6-tsx"&gt;msw.test.6.tsx&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;As you can see in the code above, we’re using the &lt;code&gt;server.use()&lt;/code&gt; &lt;a href="https://mswjs.io/docs/api/setup-server/use"&gt;function&lt;/a&gt;. This function prepends request handlers to the current server instance. This means we are using everything that has been set up in the &lt;code&gt;tools/jest/server.js&lt;/code&gt; file, and we’re adding a specific request handler for a specific URL.&lt;/p&gt;

&lt;p&gt;Now, to use this helper function in a test, the test author would need to write something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// src/FancyHomepageFeature/__tests__/FancyHomePage.test.js
import { FancyHomePage } from "../FancyHomePage";
import { setupHomeHandlers } from "./msw/mswHandlers";

describe("&amp;lt;FancyHomePage /&amp;gt;", () =&amp;gt; {
  beforeEach(() =&amp;gt; setupHomeHandlers());
  test("displays homepage data", async () =&amp;gt; {
    // Render homepage with backend data
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/marta-pinkowska/f3fbcb053710b376643a98215b7f31e0#file-msw-test-7-tsx"&gt;msw.test.7.tsx&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;The test author must import the server helper and run it in a &lt;code&gt;beforeEach&lt;/code&gt; block.&lt;/p&gt;

&lt;p&gt;Tests in this particular test suite will now look into the &lt;code&gt;homeHandlers&lt;/code&gt; array when the components need something from the &lt;em&gt;&lt;a href="https://fancy-app.com/homepage-data"&gt;https://fancy-app.com/homepage-data&lt;/a&gt;&lt;/em&gt; endpoint, while other test suites remain unaffected by this change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing errors
&lt;/h2&gt;

&lt;p&gt;What if you would like to test that your website can handle network errors on specific endpoints? &lt;/p&gt;

&lt;p&gt;Let’s add another helper function to the &lt;code&gt;FancyHomepageFeature/msw/mswHandlers.js file&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// src/FancyHomepageFeature/msw/mswHandlers.js

import { rest } from 'msw';
import { server } from '../tools/jest/server';

//...

export const setupFaultyHomeHandlers = () =&amp;gt; {
  server.use(
    rest.get('https://fancy-app.com/homepage-data', (_req, res, ctx) =&amp;gt; {
      return res(ctx.status(200), ctx.json({weirdDataType: 'something went wrong'}));
    }),
  );
};

export const setupFailedHomeHandlers = () =&amp;gt; {
  server.use(
    rest.get('https://fancy-app.com/homepage-data', (_req, res) =&amp;gt; {
      return res.networkError('Failed to connect');
    })
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/marta-pinkowska/e0c347c0e8bc6b0baf101f799b15c37a#file-msw-test-8-tsx"&gt;msw.test.8.tsx&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;We can add tests for the scenarios described above: &lt;strong&gt;what should happen if the server returns a successful response, but the values are unexpected?&lt;/strong&gt; How should the website behave if there is a network error? &lt;/p&gt;

&lt;p&gt;Let’s see those tests in action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// src/FancyHomepageFeature/__tests__/FancyHomePage.test.js
import { FancyHomePage } from "../FancyHomePage";
import {
  setupHomeHandlers,
  setupFaultyHomeHandlers,
  setupFailedHomeHandlers,
} from "./msw/mswHandlers";

describe("&amp;lt;FancyHomePage /&amp;gt;", () =&amp;gt; {
  beforeEach(() =&amp;gt; setupHomeHandlers());
  test("displays homepage data", async () =&amp;gt; {
    // Render homepage with backend data
  });
});

describe("&amp;lt;FancyHomePage /&amp;gt; - faulty data", () =&amp;gt; {
  beforeEach(() =&amp;gt; setupFaultyHomeHandlers());
  test("displays readable error when receiving unexpected data", async () =&amp;gt; {
    // Render homepage with error information
  });
});

describe("&amp;lt;FancyHomePage /&amp;gt; - network error", () =&amp;gt; {
  beforeEach(() =&amp;gt; setupFailedHomeHandlers());
  test("displays network error", async () =&amp;gt; {
    // Render homepage with network error information
  });
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/marta-pinkowska/3ec5f99e31331926859d0cb2661dc59b#file-msw-test-8-tsx"&gt;msw.test.8.tsx&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;h2&gt;
  
  
  Request handler overrides
&lt;/h2&gt;

&lt;p&gt;If you read the MSW documentation carefully, you may be tempted to use the &lt;a href="https://mswjs.io/docs/api/setup-server/use#one-time-override"&gt;one-time override&lt;/a&gt; (&lt;code&gt;res.once()&lt;/code&gt;) for testing errors. &lt;/p&gt;

&lt;p&gt;We have tried using this strategy in our codebase. We have found that using &lt;code&gt;res.once()&lt;/code&gt; is &lt;code&gt;counter-intuitive to the test author&lt;/code&gt;. If the test setup includes this one-time override, but the test suite has more than one test, only the first test will behave as expected. &lt;/p&gt;

&lt;p&gt;It may take the test author quite some time and great detective work to figure out that all his tests were correct, but the MSW handlers were prepared to handle only one request. If I was ever to use &lt;code&gt;res.once()&lt;/code&gt;, it would only be directly in a test file, where it’s easily visible, and never in setup files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Response object overrides
&lt;/h2&gt;

&lt;p&gt;There is another type of override that I do recommend using - &lt;strong&gt;response object overrides&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Let’s say you would like to test your network request with different, successful responses. You could write separate functions using &lt;code&gt;server.use()&lt;/code&gt;, but that’s a lot of repetitive work. &lt;/p&gt;

&lt;p&gt;One of my colleagues, &lt;a href="https://www.callstack.com/team/jan-jaworski"&gt;Jan Jaworski&lt;/a&gt;, came up with a very elegant solution to this problem. He created a helper function that could &lt;strong&gt;accept override data and use it in the response object thanks to the spread operator&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;The function looked roughly like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const setupSmartMswHelper = (override = {}) =&amp;gt; {
  server.use(
    rest.get("https://fancy-app.com/return-some-data", (req, res, ctx) =&amp;gt; {
      return res(
        ctx.status(200),
        ctx.json({
          fancyData: "Im so fancy!",
          moreData: "You already know",
          ...override,
        })
      );
    })
  );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/marta-pinkowska/8d9e056ca1152fd3ec7d269063263822#file-msw-test-9-tsx"&gt;msw.test.9.tsx&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;Here’s how this helper function would be used in a test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// src/FancyHomepageFeature/__tests__/FancyHomePage.test.js
//...
test("handles updated data", async () =&amp;gt; {
  setupSmartMswHelper({
    moreData: "Cant you taste this gold?",
  });
  //...
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/marta-pinkowska/eeead2f44adf328dad24b91e5666671f#file-msw-test-10-tsx"&gt;msw.test.10.tsx&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;This strategy is especially useful for &lt;strong&gt;big data objects we don’t want to re-type multiple times&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing errors - bonus content
&lt;/h2&gt;

&lt;p&gt;Since we started testing network errors, we discovered the terminal output got polluted with many &lt;code&gt;console.error&lt;/code&gt; messages. These error messages were expected, and we didn’t want them hiding real (as in UNexpected) errors.&lt;/p&gt;

&lt;p&gt;We decided to add a &lt;code&gt;console.error&lt;/code&gt; override in the Jest setup file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// tools/jest/setupTests.js
const error = console.error;

console.error = (...args) =&amp;gt;
  // Suppress error messages regarding network error in tests
  /Error: Request failed with status code 500/m.test(
    args[0]
  )
    ? void 0
    : error(...args);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/marta-pinkowska/4130ca8d7336d063e41f8cab25f83496#file-msw-test-11-tsx"&gt;msw.test.11.tsx&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;Thanks to this little function, we hid only the specific console errors we were sure about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;If you were to take away only one thing from this blog post, I sincerely hope it would be the notion that &lt;strong&gt;MSW is a great tool worth trying, even in a big project&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The solutions I described worked great in a real project. They may not be 100% ideal for your needs, but I hope you find some inspiration here to create &lt;strong&gt;the best, most comfortable, and developer-friendly test setup possible&lt;/strong&gt;. At the end of the day, we all want to feel like the people at the end of infomercials, no?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was originally published at &lt;a href="https://www.callstack.com/blog/guide-to-mock-service-worker-msw"&gt;callstack.com&lt;/a&gt; on September 27, 2022.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>appdevelopment</category>
      <category>testing</category>
    </item>
    <item>
      <title>How to Use Module Federation with Re.Pack 3</title>
      <dc:creator>Callstack Engineers</dc:creator>
      <pubDate>Wed, 12 Oct 2022 08:54:45 +0000</pubDate>
      <link>https://dev.to/callstackengineers/how-to-use-module-federation-with-repack-3-555b</link>
      <guid>https://dev.to/callstackengineers/how-to-use-module-federation-with-repack-3-555b</guid>
      <description>&lt;p&gt;by &lt;a href="https://www.callstack.com/team/jakub-binda" rel="noopener noreferrer"&gt;Jakub Binda&lt;/a&gt; &amp;amp; Andrew Andilevko&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Along with the release of &lt;a href="https://www.callstack.com/open-source/re-pack" rel="noopener noreferrer"&gt;Re.Pack&lt;/a&gt; v.3 there comes a huge update for the library - stable support for Module Federation.&lt;/p&gt;

&lt;p&gt;This feature can be a powerful ally for development departments, especially when it comes to building complex apps with Micro-Frontend architecture, requiring multiple teams to deliver the whole thing. &lt;/p&gt;

&lt;p&gt;In this article, you’ll find out&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what’s the idea behind Module Federation,&lt;/li&gt;
&lt;li&gt;and how to use Module Federation with Re.Pack 3.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The idea behind Module Federation
&lt;/h2&gt;

&lt;p&gt;Module Federation was first introduced in &lt;a href="https://webpack.js.org/concepts/module-federation/" rel="noopener noreferrer"&gt;Webpack 5&lt;/a&gt;. It’s a functionality that allows for code-splitting and sharing the split code parts (chunks) between loosely coupled applications. It also helps distributed teams to ship large applications faster. And, along with its latest update, Re.Pack 3 supports this functionality out-of-the-box.&lt;/p&gt;

&lt;p&gt;Module Federation is one of the approaches to creating &lt;strong&gt;Micro-frontends&lt;/strong&gt; architecture for your application which makes the functionality a great ally in, for example, &lt;a href="https://www.callstack.com/super-app-development" rel="noopener noreferrer"&gt;super app development&lt;/a&gt; or creating features on demand. &lt;/p&gt;

&lt;h2&gt;
  
  
  Micro-frontends
&lt;/h2&gt;

&lt;p&gt;Going briefly through the Micro-Frontends working scheme, there are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;the host app&lt;/strong&gt; that runs firstly on the device, &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;and Micro-frontend (MFE)&lt;/strong&gt; apps that are used by the host app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That means each container (MFE) that is used by the host application could be deployed and maintained independently. The host apps are able to reflect changes in Micro-frontend immediately with no need for re-deploy until the changes are connected to the JS only.&lt;/p&gt;

&lt;p&gt;Accessing remote JS code exposed by MFE is the key feature of Module Federation and the process is called &lt;strong&gt;Runtime Deployment&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flznbsu9y9px8v6cfpnic.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flznbsu9y9px8v6cfpnic.png" alt="Image description" width="800" height="273"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Scheme 1. Module Federation in the app&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to use Module Federation in Re.Pack&lt;/strong&gt;&lt;br&gt;
If you are familiar with the Webpack config for Module Federation on the web environment, you will notice a similarity in the configuration using Re.Pack. The major difference is to take into account mobile platform / React Native specifics.&lt;/p&gt;

&lt;p&gt;Let’s assume that we have the host application, two container applications, and one module used in the first container application. Each of the apps could be deployed independently, but all of them are bound using Webpack config.&lt;/p&gt;

&lt;p&gt;The most interesting properties for us from this config are &lt;strong&gt;plugins&lt;/strong&gt;. It is an array of all the required Webpack plugins. As you can see from the code snippet below, Re.Pack exports a &lt;code&gt;ModuleFederationPlugin&lt;/code&gt; plugin that enables Module Federation functionality:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new Repack.plugins.ModuleFederationPlugin({
        name: 'host',
        shared: {
          react: {
            ...Repack.Federated.SHARED_REACT,
            requiredVersion: '17.0.2',
          },
          'react-native': {
            ...Repack.Federated.SHARED_REACT_NATIVE,
            requiredVersion: '0.68.2',
          },
        },
      })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/136e6a205619915099d1f09196e5f90c#file-host-app-webpack-config-module-federation-plugin-js" rel="noopener noreferrer"&gt;Host app Webpack config Module Federation plugin.js&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Code snippet 1. Host app Webpack config Module Federation plugin&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new Repack.plugins.ModuleFederationPlugin({
        name: 'app1',
        exposes: {
          './App': './src/App.tsx',
          './Text': './src/Text.tsx',
          './foo': './src/foo.ts',
        },
        shared: {
          react: {
            ...Repack.Federated.SHARED_REACT,
            eager: STANDALONE,
          },
          'react-native': {
            ...Repack.Federated.SHARED_REACT_NATIVE,
            eager: STANDALONE,
            requiredVersion: '0.68.2',
          },
        },
        remotes: {
          module1: 'module1@dynamic',
        },
      })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/ed59a8eb8a30bda1ef670c446eaa6a00#file-remote-container-1-webpack-config-module-federation-plugin-js" rel="noopener noreferrer"&gt;Remote Container 1 Webpack config Module Federation plugin.js&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Code snippet 2. Remote Container 1 Webpack config Module Federation plugin&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new Repack.plugins.ModuleFederationPlugin({
        name: 'module1',
        exposes: {
          './Root': './src/Root.tsx',
          './baz': './src/baz.ts',
        },
        shared: {
          react: {
            ...Repack.Federated.SHARED_REACT,
            eager: STANDALONE,
          },
          'react-native': {
            ...Repack.Federated.SHARED_REACT_NATIVE,
            eager: STANDALONE,
            requiredVersion: '0.68.2',
          },
        },
        remotes: {
          app1: 'app1@dynamic',
        },
      })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/4be57c16c85df2173015c693bb1566a0#file-module-app-webpack-config-module-federation-plugin-js" rel="noopener noreferrer"&gt;Module app Webpack config Module Federation plugin.js&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Code snippet 3. Module app Webpack config Module Federation plugin&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Going through the properties in the Module Federation plugin config, we can find the same ones in all of the apps. The &lt;code&gt;name&lt;/code&gt; property is required, so we have to provide a unique name for each of our apps. Then, we will use it across the app for importing federated modules. The next common property is called &lt;code&gt;shared&lt;/code&gt;. This array contains libraries and provides Webpack information regarding the libraries that should be shared in other applications. Also, they should have only one instance across the apps. Re.Pack provides default settings for React and React Native libraries in &lt;code&gt;shared&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;So, until there are no more other libraries that should be shared, this property could be skipped. Dependency defined inside shared property might be also set as &lt;code&gt;eager&lt;/code&gt;, which doesn’t put the modules in an async chunk, but provides them synchronously. That’s why it is combined with &lt;code&gt;STANDALONE&lt;/code&gt; env which should be &lt;code&gt;true&lt;/code&gt; when a remote app is run as its standalone version. Otherwise shared modules won’t be available in the initial bundle and the app is likely to crash. &lt;/p&gt;

&lt;p&gt;As you can see on the code snippets above, all the plugins’ configs, except the host app, have &lt;code&gt;exposes&lt;/code&gt; property. This is a list of modules that the application will export as remote to another application. The host app can only import remote modules and cannot have pre-defined ‘exposes’ or ‘remotes’ properties in Webpack config. However, MFEs can do both, expose and import remote modules at the same time. &lt;/p&gt;

&lt;p&gt;While ‘exposes’ and ‘remotes’ properties are sufficient to support Module Federation in web apps, it’s not enough in a mobile environment. For Re.Pack, we have to add one more thing to handle fetched scripts from remote - a resolver. That’s why the &lt;code&gt;ScriptManager&lt;/code&gt; was introduced in Re.Pack 3.&lt;/p&gt;

&lt;p&gt;This is a manager that eases the resolution, downloading, and executing additional code from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;arbitrary JavaScript scripts&lt;/li&gt;
&lt;li&gt;Webpack chunks&lt;/li&gt;
&lt;li&gt;Webpack bundles&lt;/li&gt;
&lt;li&gt;Webpack MF containers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To make &lt;code&gt;ScriptManager&lt;/code&gt; resolve our remote scripts properly, we need to pass URLs to remote locations that those scripts will be available to fetch. They should be passed in proper object shape accepted by the createURLResolver method from the Federated module. In a very basic example, URLs might be hardcoded and the implementation is presented in the snippet below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const resolveURL = Federated.createURLResolver({
  containers: {
    app1: 'http://localhost:9000/[name][ext]',
    app2: 'http://localhost:9001/[name][ext]',
    module1: 'http://localhost:9002/[name][ext]',
  },
});

ScriptManager.shared.addResolver(async (scriptId, caller) =&amp;gt; {
  let url;
  if (caller === 'main') {
    url = Script.getDevServerURL(scriptId);
  } else {
    url = resolveURL(scriptId, caller);
  }

  if (!url) {
    return undefined;
  }

  return {
    url,
    cache: false,
    query: {
      platform: Platform.OS,
    },
  };
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/22ac442379284e7acd1473965c38f579#file-scriptmanager-usage-inside-host-application-ts" rel="noopener noreferrer"&gt;ScriptManager usage inside host application.ts&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Code snippet 4. ScriptManager usage inside the host application&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;However, there is an option to provide remote containers URLs dynamically. That means removing hardcoded URLs and fetching them from external service right in &lt;code&gt;addResolver&lt;/code&gt;. Implementing the external service is optional but might become very useful on a larger scale. It allows to manage remote containers' URLs from outside of the host app and to switch them without the need for the host app re-deployement. Furthermore, it might help to handle fetching theproper version of MFEs inside the host app when a version management system is required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ScriptManager.shared.addResolver(async (scriptId, caller) =&amp;gt; {
  let url;
    const containers = await fetchURLs();
    const resolveURL = Federated.createURLResolver({
      containers,
    });

  if (caller === 'main') {
    url = Script.getDevServerURL(scriptId);
  } else {
    url = resolveURL(scriptId, caller);
  }

  if (!url) {
    return undefined;
  }

  return {
    url,
    cache: false,
    query: {
      platform: Platform.OS,
    },
  };
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/1267869dff1de6fdb57507d4f52e815d#file-scriptmanager-usage-with-dynamic-urls-js" rel="noopener noreferrer"&gt;ScriptManager usage with dynamic URLs.js&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Code snippet 4.1. ScriptManager usage with dynamic URLs&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After setting up the &lt;code&gt;ScriptManager&lt;/code&gt;, we can use Module Federation functionality in the code. Here is the &lt;code&gt;App.tsx&lt;/code&gt; file from the host application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// eslint-disable-next-line import/no-extraneous-dependencies
import { Federated } from '@callstack/repack/client';
import React from 'react';
import { Text, SafeAreaView } from 'react-native';

const App1 = React.lazy(() =&amp;gt; Federated.importModule('app1', './App'));
const App2 = React.lazy(() =&amp;gt; Federated.importModule('app2', './App'));

export default function App() {
  return (
    &amp;lt;SafeAreaView&amp;gt;
      &amp;lt;Text&amp;gt;Host App&amp;lt;/Text&amp;gt;
      &amp;lt;React.Suspense fallback={&amp;lt;Text&amp;gt;Loading app1...&amp;lt;/Text&amp;gt;}&amp;gt;
        &amp;lt;App1 /&amp;gt;
      &amp;lt;/React.Suspense&amp;gt;
      &amp;lt;React.Suspense fallback={&amp;lt;Text&amp;gt;Loading app2...&amp;lt;/Text&amp;gt;}&amp;gt;
        &amp;lt;App2 /&amp;gt;
      &amp;lt;/React.Suspense&amp;gt;
    &amp;lt;/SafeAreaView&amp;gt;
  );
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/538d0afc7e037e144a1693bed49a9ba7#file-app-tsx-code-from-host-application-tsx" rel="noopener noreferrer"&gt;App.tsx code from host application.tsx&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;The imports are async, so we should wait till the script will be downloaded, resolved by &lt;code&gt;ScriptManager&lt;/code&gt;, and ready to use. So, we added &lt;code&gt;React.lazy&lt;/code&gt; and &lt;code&gt;React.Suspense&lt;/code&gt; syntax for handling async imports. React.Suspense has the fallback property that allows showing loader component to the users during loading scripts. To dynamically import remote modules in the host app, we also used the utility function &lt;code&gt;importModule&lt;/code&gt; from &lt;code&gt;Federated&lt;/code&gt; namespace, to provide the correct container and module name.&lt;/p&gt;

&lt;p&gt;But, let’s take a look at the previously presented code from code snippet 2. There is remotes property under the Module Federation plugin in Webpack config. It helps to use the same syntax as for static imports inside app1 when importing modules from remote containers. Also, it’s worth mentioning that the component name needs to be prefixed with the remote container name. In this case, it’s module1/Root. According to what was written before - the remotes property can be used only in MFEs but anyway, it should still use &lt;code&gt;React.Suspense&lt;/code&gt; when rendering remote containers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import * as React from 'react';
import { Text } from 'react-native';

// eslint-disable-next-line import/no-unresolved
import Module1 from 'module1/Root';
import { foo } from './foo';

export default function App() {
  const [fooText, setFooText] = React.useState&amp;lt;string&amp;gt;('');

  React.useEffect(() =&amp;gt; {
    (async () =&amp;gt; {
      try {
        const fooText = await foo();
        setFooText(fooText);
      } catch {
        setFooText('Failed to get foo text');
      }
    })();
  }, []);

  return (
    &amp;lt;&amp;gt;
      &amp;lt;Text&amp;gt;App 1&amp;lt;/Text&amp;gt;
      &amp;lt;React.Suspense fallback={&amp;lt;Text&amp;gt;Loading module1...&amp;lt;/Text&amp;gt;}&amp;gt;
        &amp;lt;Module1 /&amp;gt;
      &amp;lt;/React.Suspense&amp;gt;
      &amp;lt;Text&amp;gt;{fooText}&amp;lt;/Text&amp;gt;
    &amp;lt;/&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/25df7f90ea4f7d7083487128c94450ba#file-app-tsx-code-from-app1-application-tsx" rel="noopener noreferrer"&gt;App.tsx code from app1 application.tsx&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Code snippet 6. App.tsx code from app1 application&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In code snippet 3 there is also a defined remotes property that allows importing modules exposed by app1. This pattern is called bi-directional import. It won’t be possible outside the Module Federation when importing module B in module A and module A in module B at the same time because of circular dependencies. However, Module Federation allows it and it’s totally fine until both modules are imported from different MFEs. The only thing that developers have to keep in mind is that it might be easy to end up with an endless loop e.g. by calling one function by another as presented in the code snippet below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let counter = 3;

export async function baz() {
  if (counter &amp;lt;= 0) {
    return 'end';
  }

  // eslint-disable-next-line import/no-unresolved
  const { foo } = await import('app1/foo');

  counter--;
  return `baz + ${await foo()}`;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/37d9f1ff532e1166457fbc1440452c89#file-baz-function-inside-module1-which-uses-foo-function-from-app1-tsx" rel="noopener noreferrer"&gt;baz function inside module1 which uses foo function from app1.tsx&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Code snippet 7. baz function inside module1 which uses foo function from app1&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Please notice that the foo function from app1 uses baz function from module1. So as mentioned above, circular dependencies are working perfectly fine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// eslint-disable-next-line import/no-unresolved
import { baz } from 'module1/baz';

export async function foo() {
  return `foo + ${await baz()}`;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://gist.github.com/callstack-bot/0bef51519142d66c15bb7b2bec736cff#file-foo-function-from-app1-tsx" rel="noopener noreferrer"&gt;foo function from app1.tsx&lt;/a&gt; hosted with ❤ by GitHub&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Code snippet 8. foo function from app1&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;On code snippet 7, there is a counter variable that prevents an endless loop caused by calling &lt;code&gt;foo&lt;/code&gt; by &lt;code&gt;baz&lt;/code&gt; and &lt;code&gt;baz&lt;/code&gt; by &lt;code&gt;foo&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Module Federation is a powerful feature implemented in Webpack 5 and carefully migrated to Re.Pack 3 package.&lt;/p&gt;

&lt;p&gt;Thanks to its functionalities, Module Federation can be a great ally for large development teams working on complex products, like super apps. The main benefits of Module Federation are&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Independent deployment. No need to re-deploy host application on remote containers changes and re-deployment&lt;/li&gt;
&lt;li&gt;Separating huge development teams. As every container could be deployed independently each team could work on their container &lt;/li&gt;
&lt;li&gt;Sharing the code between tightly loosely coupled applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;This article was originally published at &lt;a href="https://www.callstack.com/blog/module-federation-with-re-pack-3" rel="noopener noreferrer"&gt;callstack.com&lt;/a&gt; on October 4, 2022.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>reactnative</category>
      <category>repack</category>
      <category>modulefederation</category>
    </item>
    <item>
      <title>Continuous App Performance Monitoring Made Simple with Reassure</title>
      <dc:creator>Callstack Engineers</dc:creator>
      <pubDate>Mon, 10 Oct 2022 15:43:21 +0000</pubDate>
      <link>https://dev.to/callstackengineers/continuous-app-performance-monitoring-made-simple-with-reassure-2o67</link>
      <guid>https://dev.to/callstackengineers/continuous-app-performance-monitoring-made-simple-with-reassure-2o67</guid>
      <description>&lt;p&gt;by &lt;a href="https://www.callstack.com/team/michal-pierzchala"&gt;Michał Pierzchała&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Have you ever heard about entropy? &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--r0etJThv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tlbbn9a9d94fbba4zogg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r0etJThv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tlbbn9a9d94fbba4zogg.png" alt="Image description" width="880" height="359"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;As Stephen Hawking framed it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You may see a cup of tea fall off a table and break into pieces on the floor... But you will never see the cup gather itself back together and jump back on the table. The increase of disorder, or entropy, is what distinguishes the past from the future, giving a direction to time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In other words: &lt;strong&gt;things will fall apart eventually when unattended&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But let’s not get too depressed or comfortable with things just turning into chaos naturally. We can and do fight back against it. We can exert effort to create useful types of order resilient enough to withstand the unrelenting pull of entropy by expending energy. &lt;/p&gt;

&lt;p&gt;Let’s start from the beginning.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does a development cycle look like?
&lt;/h2&gt;

&lt;p&gt;When developing software, we feel entropy. That’s why we usually put extra effort into following some development cycle.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--v-lidqzW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e9niiub86beci7ktwtqt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--v-lidqzW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e9niiub86beci7ktwtqt.png" alt="Image description" width="880" height="880"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example, we start with adding a new feature. During development, we sprinkle it with a bunch of tests. When we’re done, we send it to QAs. They accept it and promote our code to a production release channel. And we’re back to adding another feature.&lt;/p&gt;

&lt;p&gt;That’s quite a simplified version of what we usually do. Because, among other things, &lt;strong&gt;we don’t take into account that wild bugs may appear!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tDXy-L3y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m8mbzuj5d5uf5le3vbgc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tDXy-L3y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m8mbzuj5d5uf5le3vbgc.png" alt="Image description" width="880" height="880"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our experience tells us to keep it cool, identify the root cause, and &lt;strong&gt;add a regression test&lt;/strong&gt; so it never breaks again. Then we send it to QA once again, ship it, and go back to adding features.&lt;/p&gt;

&lt;p&gt;We’re happier with our workflow now; it works well. We’re adding feature after feature. Our app release cycle is so well designed that even adding ten new developers doesn’t slow us down. Until we take a look at our app reviews:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xa0jxTJA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/npm7sdhc4aaftc48sho5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xa0jxTJA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/npm7sdhc4aaftc48sho5.jpg" alt="Image description" width="880" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why do you need to continuously monitor the performance of your app?
&lt;/h2&gt;

&lt;p&gt;We realize that our perfect workflow based on Science™, our experience, and “best practices,” which was supposed to prevent our app from falling apart, is not resilient to particular bugs. Namely, &lt;strong&gt;performance regressions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Our codebase doesn’t have the tools to fight these. We know how to fix the issues once spotted, but &lt;strong&gt;we have no way to spot them before they hit our users&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Coming back to our entropy example, in other words, we could say that performance will fall apart eventually when unattended. &lt;strong&gt;If we don’t do anything to optimize our app&lt;/strong&gt; while adding new code and letting the time go by, &lt;strong&gt;it will certainly get slower&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;We don’t know when it will happen. Maybe tomorrow, maybe in a week,or in a year.&lt;/p&gt;

&lt;p&gt;If only there’s been an established way of catching some of the regressions early in the development process… &lt;/p&gt;

&lt;p&gt;Wait a minute, there is!&lt;/p&gt;

&lt;h2&gt;
  
  
  How to monitor app performance regression?
&lt;/h2&gt;

&lt;p&gt;With fully automated regression tests! Tests that run in a remote environment on every code change, and that already are a part of our development process. &lt;/p&gt;

&lt;p&gt;Before we pick the best tool for the job, let’s consider the impact and what’s worth testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The most common React (Native) performance issues
&lt;/h2&gt;

&lt;p&gt;As with test coverage, there’s a healthy ratio that we strive for to provide us with the best value for the lowest amount of effort. We want to target regressions that are most likely to hit our users.&lt;/p&gt;

&lt;p&gt;At Callstack, we identified React Native performance issues our developers deal with daily.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gzj4AGMP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e22jhl1w6oshzxppm2yw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gzj4AGMP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e22jhl1w6oshzxppm2yw.png" alt="Image description" width="880" height="880"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Slow lists and images, SVGs, React Context misusage, re-renders, slow TTI, are among the most common ones. If we look at this list from the origin of the issue point of view, we’ll notice that a vast majority of these come from the JS side. &lt;/p&gt;

&lt;p&gt;We estimate that most of the time our developers spend fixing performance issues, around &lt;strong&gt;80%, originating from the JS realm, especially from React misusage&lt;/strong&gt;. Only the rest is bridge communication overhead and native code – like image rendering or database operations – working inefficiently. &lt;/p&gt;

&lt;p&gt;It’s fair to say that we expect to encounter these problems in both React web apps and React Native mobile apps.&lt;/p&gt;

&lt;p&gt;We did our research and didn’t find any library allowing us to reliably write performance regression tests for React or React Native. We’d like to have it integrated with the existing ecosystem of libraries we’re using. &lt;/p&gt;

&lt;p&gt;The perfect library for measuring performance regression should: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;measure render times and count reliably, &lt;/li&gt;
&lt;li&gt;have a CI runner, &lt;/li&gt;
&lt;li&gt;generate readable and parseable reports, &lt;/li&gt;
&lt;li&gt;provide helpful insights for code review, and &lt;/li&gt;
&lt;li&gt;have a stable design based on React public API.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using our experience from developing the &lt;a href="https://callstack.github.io/react-native-testing-library/"&gt;React Native Testing Library&lt;/a&gt;, we created &lt;strong&gt;&lt;a href="https://www.callstack.com/open-source/reassure?utm_campaign=Reassure&amp;amp;utm_source=dev.to&amp;amp;utm_content=reassure_page"&gt;Reassure&lt;/a&gt;—a performance regression testing companion for React and React Native components&lt;/strong&gt;. We developed it in partnership with Entain – one of the world’s largest sports betting and gaming groups.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does Reassure work?
&lt;/h2&gt;

&lt;p&gt;Reassure builds on top of your existing React Testing Library setup and sprinkles it with an unobtrusive performance measurement API.&lt;/p&gt;

&lt;p&gt;It’s designed to be &lt;strong&gt;run on a remote server environment&lt;/strong&gt; as a part of your continuous integration suite. &lt;/p&gt;

&lt;p&gt;To increase the stability of results and decrease flakiness, Reassure will run your tests once for the current branch and another for the base branch. &lt;/p&gt;

&lt;p&gt;In the near future, with sufficiently stable CI, we’ll be able only to run the tests once and compare the results with the ones from the past.&lt;/p&gt;

&lt;p&gt;To ensure a delightful Developer Experience, Reassure &lt;strong&gt;integrates with GitHub to enhance the code review process&lt;/strong&gt;. Currently, we leverage Danger.js as our bot backend, but in the future, we’d like to prepare a plug-and-play GitHub Action.&lt;/p&gt;

&lt;p&gt;Let’s take a look at what it takes to incorporate Reassure into your regression testing pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write performance regression tests
&lt;/h2&gt;

&lt;p&gt;Before you write your first test, you need to install Reassure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add --dev reassure
# or 
npm install --save-dev reassure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can start writing your performance tests. Let’s take a look at this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// counter.perf-test.tsx
test('Count increments on press', async () =&amp;gt; {
  const scenario = async (screen: RenderAPI) =&amp;gt; {
    const button = screen.getByText('Action');

    await screen.findByText('Count: 0’);
    fireEvent.press(button);
    fireEvent.press(button);
    await screen.findByText('Count: 2');
  };

  const stats = await measurePerformance(
    &amp;lt;Counter /&amp;gt;, 
    { scenario, runs: 20 }
  );
  await writeTestStats(stats);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We created a new file with “.perf-test.tsx” extension that reuses our component test in a &lt;code&gt;scenario&lt;/code&gt; function. It takes an optional &lt;code&gt;screen&lt;/code&gt; argument which is, in fact, a return value of Testing Library’s &lt;code&gt;render&lt;/code&gt; helper. &lt;/p&gt;

&lt;p&gt;The scenario is then used by the &lt;code&gt;measurePerformance&lt;/code&gt; method from Reassure, which renders our Counter component, in this case, 20 times, letting the React Profiler to measure render count and duration times for us. In the end, we call &lt;code&gt;writeTestStats&lt;/code&gt; to save this data to the filesystem.&lt;/p&gt;

&lt;p&gt;And that’s usually all you have to write. Copy-paste your existing tests, adjust, and enjoy your app being a little bit safer with every test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run Reassure
&lt;/h2&gt;

&lt;p&gt;Now that you have your first performance regression test created, it’s time to run Reassure somehow! It’s important to mention that you need to measure the performance of two versions of your code – the current (modified one) and the baseline. Reassure will compare the two to determine whether there are any regressions in the current code version.&lt;/p&gt;

&lt;p&gt;Since the goal is to run the performance tests on the CI environment, we want to automate this task. To do that, you will need to create a performance testing script, like this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Gather baseline perf measurements
git switch main
yarn install --force
yarn reassure --baseline

# Gather current perf measurements &amp;amp; compare results
git switch -
yarn install --force
yarn reassure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And save it in your repository, e.g. &lt;code&gt;as reassure-tests.sh&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The script switches to your base branch, installs dependencies, and runs &lt;code&gt;yarn reassure --baseline&lt;/code&gt; to gather the base metrics. Once done, it switches back to your current feature branch, installs dependencies again, as those might have changed, and runs &lt;code&gt;yarn reassure&lt;/code&gt; again.&lt;/p&gt;

&lt;h2&gt;
  
  
  See the performance test results
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3cfBtSLp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tsvw9pj0mth3q2116w9a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3cfBtSLp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tsvw9pj0mth3q2116w9a.png" alt="Image description" width="880" height="703"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Having all that data, Reassure can present the render duration times as statistically significant or meaningless.&lt;/p&gt;

&lt;p&gt;Apart from render times, another useful metric that may easily degrade is render counts, which we get for free from React Profiler. &lt;/p&gt;

&lt;p&gt;All this information is stored in a JSON format for further analysis and Markdown for readability.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mKEQm8hO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y15prrg3fo6998r82eh6.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mKEQm8hO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y15prrg3fo6998r82eh6.jpg" alt="Image description" width="880" height="468"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We use the markdown output as a source for the GitHub commenting bot powered by &lt;a href="https://danger.systems/js/"&gt;DangerJS&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;This is by far our favorite and recommended usage of this tool, as it enriches the code review process while allowing us to alleviate the instability of the CI we’re using. &lt;/p&gt;

&lt;h2&gt;
  
  
  What have we learned from developing Reassure?
&lt;/h2&gt;

&lt;p&gt;Developing Reassure has taught us some valuable lessons about&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;running benchmarks with Node.js, and&lt;/li&gt;
&lt;li&gt;measuring precision in JavaScript. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s dive into it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges of running benchmarks with Node.js
&lt;/h2&gt;

&lt;p&gt;Running benchmarks is not a piece of cake even in non-JS environments, but it’s &lt;strong&gt;particularly tricky with Node.js&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;The key is &lt;strong&gt;embracing stability and avoiding flakiness&lt;/strong&gt;. Operating in a JavaScript VM, we need to considerJIT, garbage collection, and module resolution caching. &lt;/p&gt;

&lt;p&gt;Then we have a cost of concurrency that our test runner embraces for execution speed. We need to pick what to average, what to percentile, and how to apply statistical analysis. And a lot more.&lt;/p&gt;

&lt;p&gt;Running tests once or twice is not enough to make sure our measurement results make sense mathematically. Taking other things into account, ten times is a good baseline for our use case. Then, to determine the probability of the result being statistically significant, we need to calculate the z-score, which needs the mean value (or average), divergence, and standard deviation. &lt;/p&gt;

&lt;p&gt;Reassure handles all of that for you, so you don’t even have to think about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you probably didn’t know about measurement precision in JavaScript
&lt;/h2&gt;

&lt;p&gt;Measurement precision is another tricky topic in the JS land. &lt;/p&gt;

&lt;p&gt;React Profiler uses &lt;code&gt;performance.now()&lt;/code&gt; API to reliably measure rendering time. Node.js implements the W3C recommendation, which—due to privacy concerns—requires a resolution of no less than 5 microseconds. &lt;/p&gt;

&lt;p&gt;We can measure a 1 ms render with at least 0.5% error. This is usually good enough. But because many lighter components render faster than 1 ms, and due to the variable stability of the machine, we run them at least ten times anyway and let you configure that as well.&lt;/p&gt;

&lt;p&gt;Now, module resolution caching is great for our Node.js apps. &lt;/p&gt;

&lt;p&gt;But it bit us when developing the library. As it turned out, &lt;strong&gt;subsequent execution of the same component often resulted in even ten times slower runs&lt;/strong&gt;. As you can imagine, averaging that would make the results unreliable. So we drop the slowest test as most likely it’s skewed by the lack of cache.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Even if you don’t have performance issues at the moment, they will appear sooner or later. We speak from our experience with many clients. Reassure will allow you to spot them once they appear. &lt;/p&gt;

&lt;p&gt;With Reassure, you can&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;test whole screens or even screen sequences&lt;/li&gt;
&lt;li&gt;perform component level tests are possible but often require more runs&lt;/li&gt;
&lt;li&gt;reuse your RNTL tests if you have them, and &lt;/li&gt;
&lt;li&gt;all established Testing Library practices apply, so let your tests resemble users’ behavior and avoid mocking anything other than I/O.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4H7LlWeM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n41a5z13zrt79w3qt80i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4H7LlWeM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n41a5z13zrt79w3qt80i.png" alt="Image description" width="880" height="799"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Due to their qualities, frontend perf tests seem to resemble end-to-end tests for our apps. And it makes sense to treat them as such in our testing trophies or pyramids.&lt;/p&gt;

&lt;p&gt;Remember that performance is not a goal. It’s a path. Walk it with confidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reassure is Open Source
&lt;/h2&gt;

&lt;p&gt;Like all of the tools we build at Callstack, Reassure is an &lt;a href="https://www.callstack.com/open-source"&gt;Open Source&lt;/a&gt; software, released under an MIT license. Feel free to check it out on &lt;a href="https://github.com/callstack/reassure"&gt;GitHub&lt;/a&gt; to see the complete installation and usage guide. And if you liked it—&lt;a href="https://github.com/callstack/reassure/stargazers"&gt;star it&lt;/a&gt;! &lt;/p&gt;

&lt;p&gt;We’re excited to see how you use it and how it helps you guard the performance of your apps. So don’t be afraid to hit the “Issues” tab to let us know.&lt;/p&gt;

&lt;p&gt;And if you want to listen to a talk with &lt;a href="https://www.callstack.com/team/michal-pierzchala"&gt;me&lt;/a&gt;, &lt;a href="https://www.callstack.com/team/maciej-jastrzebski"&gt;Maciej Jastrzębski&lt;/a&gt;, and our host, &lt;a href="https://www.callstack.com/team/lukasz-chludzinski"&gt;Łukasz Chludziński&lt;/a&gt;, take a look at one of the episodes of &lt;a href="https://www.callstack.com/podcast-react-native-show?utm_campaign=Reassure&amp;amp;utm_source=dev.to&amp;amp;utm_content=podcast_page"&gt;The React Native Show&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/8pTQKBHFs-8"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Happy testing!&lt;/p&gt;

&lt;p&gt;This article was originally published at &lt;a href="https://www.callstack.com/blog/app-performance-monitoring"&gt;callstack.com&lt;/a&gt; on September 21, 2022.&lt;/p&gt;

</description>
      <category>appperformance</category>
      <category>reactnative</category>
      <category>testing</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Why It’s Super to Have a Super App</title>
      <dc:creator>Callstack Engineers</dc:creator>
      <pubDate>Mon, 16 Aug 2021 17:29:20 +0000</pubDate>
      <link>https://dev.to/callstackengineers/why-it-s-super-to-have-a-super-app-2ien</link>
      <guid>https://dev.to/callstackengineers/why-it-s-super-to-have-a-super-app-2ien</guid>
      <description>&lt;p&gt;by Hanna Sobolewska&lt;/p&gt;

&lt;p&gt;Most mobile users have a dedicated application for a particular service or function. The more services they want to use, the more apps they need to install. No wonder that in 2020 alone there were &lt;a href="https://www.statista.com/statistics/271644/worldwide-free-and-paid-mobile-app-store-downloads/" rel="noopener noreferrer"&gt;218 billion app downloads&lt;/a&gt; (iOS App Store, Google Play and third-party Android stores combined) and the number is always growing.&lt;/p&gt;

&lt;p&gt;What if a number of these apps got consolidated into one? This is exactly the idea behind a super app – an integrated ecosystem made of dedicated services called mini apps. And yes, like so many things in the world, it was made in China.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a super app?
&lt;/h2&gt;

&lt;p&gt;A super app is a multi-purpose platform that offers a plethora of services through one mobile interface. The user can chat, check news, make daily purchases, call a taxi, and so on, and they don’t need to have separate apps to do the jobs. This is exactly a super app’s superpower: giving users the access to all functions in one place. &lt;/p&gt;

&lt;p&gt;The whole concept could be compared to a huge shopping mall that rents its space to interested retailers. When using a super app, you don’t leave the building, you just move around its premises. The “mall” saves your preferences or payment details so each retailer knows how you want to pay and where they should deliver your purchase. Once introduced, all the details are there. That also means fewer registrations as only one sign-in is required.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcmdu836stx31s5kthhci.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcmdu836stx31s5kthhci.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Examples of super apps worldwide
&lt;/h2&gt;

&lt;p&gt;The super app emerged in China. The very first one, &lt;a href="https://www.wechat.com/" rel="noopener noreferrer"&gt;WeChat&lt;/a&gt;, was initially created as a messaging app (a Chinese counterpart to WhatsApp), and it soon evolved into a marketplace of various services and offerings. Now there are hundreds of public services, mini programs, coupons, bill payment options, etc., available for &lt;a href="https://www.businessofapps.com/data/wechat-statistics/" rel="noopener noreferrer"&gt;over a billion WeChat users&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All-in-one applications took the Asian market by storm with apps such as &lt;a href="https://global.alipay.com/" rel="noopener noreferrer"&gt;Alipay&lt;/a&gt;, &lt;a href="https://www.grab.com/" rel="noopener noreferrer"&gt;Grab&lt;/a&gt;, &lt;a href="https://www.gojek.com/" rel="noopener noreferrer"&gt;Gojek&lt;/a&gt; or &lt;a href="https://paytm.com/" rel="noopener noreferrer"&gt;Paytm&lt;/a&gt;, to name just a few. It soon became an international tech trend and now the key market players are either in the process of implementing a super app, e.g. Uber, or they are planning to upgrade to a super app, e.g. &lt;a href="https://www.forbes.com/sites/ronshevlin/2021/05/26/paypal-wants-to-be-a-super-app/" rel="noopener noreferrer"&gt;Paypal&lt;/a&gt;, &lt;a href="https://www.adjust.com/blog/super-apps-mobile-marketing/" rel="noopener noreferrer"&gt;Airbnb or Amazon&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Super apps – super opportunities
&lt;/h2&gt;

&lt;p&gt;There are good reasons why most giants strive to build a one-stop portal. Having a super app comes with a wealth of benefits. To start with, it’s convenient for both the user and business owner. For the former one, it means the comfort of downloading one app to access a bunch of services and hit the big market. In practical terms, it also means less registration and login hassle.&lt;/p&gt;

&lt;p&gt;For the latter one, it definitely means a long-term reduction of development and maintenance costs. Running a super app minimizes the challenges that might occur when developing and maintaining multiple apps. All in all, it means less effort made to reach a wider audience that is very likely to make in-app purchases you will earn from.&lt;/p&gt;

&lt;p&gt;The biggest selling point, however, is the all-in-one experience itself. Creating a one-stop shop for all things users need on a daily basis is almost bound to succeed. With a good plan and &lt;a href="https://callstack.com/team/" rel="noopener noreferrer"&gt;team of trusted app developers&lt;/a&gt;, your success should be just a matter of time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fljr5vscrahs8xtvhho3o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fljr5vscrahs8xtvhho3o.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Developing super apps
&lt;/h2&gt;

&lt;p&gt;Super apps have the potential to reshape the mobile marketing landscape – no wonder that more and more companies want to develop one! How to get started? &lt;/p&gt;

&lt;p&gt;First of all, your super app still needs to focus on one main service so you need to make sure this is already settled. WeChat did start as a messaging app and over time it did evolve into a super app, but it never moved away from its original purpose. It’s still a communication tool after all – even way more advanced than it used to be.&lt;/p&gt;

&lt;p&gt;What do you need to develop a super app, technically speaking? There’s no “one and only” path to doing it right. There are different approaches and solutions, depending on whether you want to go for native or &lt;a href="https://callstack.com/cross-platform-development-services?utm_campaign=Re_Pack&amp;amp;utm_source=dev.to&amp;amp;utm_medium=subpage&amp;amp;utm_content=cross_platform_services_dev_to"&gt;cross-platform development&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Possible solutions you can adopt when designing a super app architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Native Android application with Feature Delivery&lt;/li&gt;
&lt;li&gt;Native iOS application with WebViews&lt;/li&gt;
&lt;li&gt;Cross-platform React Native application with Metro&lt;/li&gt;
&lt;li&gt;Cross-platform React Native application with Webpack and &lt;a href="https://callstack.com/re-pack?utm_campaign=Re_Pack&amp;amp;utm_source=dev.to&amp;amp;utm_medium=re_pack_subpage&amp;amp;utm_content=re_pack_subpage_clutch_link"&gt;Re.Pack&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each solution addresses different needs and comes with different benefits. Given our experience, it’s better to adopt cross-platform solutions because native applications not only use different platform languages, but also require radically different architectures.&lt;/p&gt;

&lt;p&gt;Only React Native allows us to leverage a truly cross-platform &lt;a href="https://callstack.com/blog/code-splitting-in-react-native-applications/?utm_campaign=Re_Pack&amp;amp;utm_source=dev.to&amp;amp;utm_content=code_splitting_art"&gt;code splitting&lt;/a&gt; technique which enables super apps’ implementation. Because of Webpack’s widely used and battle-tested code splitting, we can easily introduce it into React Native applications with the help of Re.Pack.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4uhtkegy5x8eaepsgm7j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4uhtkegy5x8eaepsgm7j.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Super future
&lt;/h2&gt;

&lt;p&gt;Super apps are spreading rapidly nowadays. The model is gaining popularity in &lt;a href="https://www.cnbc.com/video/2021/07/16/what-is-a-super-app-and-why-havent-they-gone-global.html" rel="noopener noreferrer"&gt;Latin America and Africa&lt;/a&gt;. Businesses from almost every market segment take interest in developing a super app. Even though the very definition of a super app may vary from continent to continent, the trend is there. And it’s there to stay!&lt;/p&gt;

&lt;p&gt;The worldwide use of super apps is spurring a new era in online shopping, payments and communication. Among the big brands that are planning to jump on the bandwagon are also social media giants such as Facebook or Twitter. That clearly means the super app landscape is going to further evolve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The super app quickly went mainstream in Asian countries – with a mobile-first population, homogeneous markets, blocked competition, and huge government support, the evolution of a multi-purpose ecosystem seemed only natural. &lt;/p&gt;

&lt;p&gt;Most probably, the super app trend will continue to grow in and out of Asia. More and more companies worldwide see the potential of retaining their users within their all-in-one application. &lt;/p&gt;

&lt;p&gt;Building a super app can give you serious competitive advantages: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The comfort of using only one place to get things done offers a unique user experience&lt;/li&gt;
&lt;li&gt;The fact you open up your space to different service providers lets you monetize your app easily &lt;/li&gt;
&lt;li&gt;The implementation of super apps gives you a stronger digital presence&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webpack</category>
      <category>reactnative</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Code Splitting in React Native Applications</title>
      <dc:creator>Callstack Engineers</dc:creator>
      <pubDate>Mon, 16 Aug 2021 16:17:05 +0000</pubDate>
      <link>https://dev.to/callstackengineers/code-splitting-in-react-native-applications-2bnh</link>
      <guid>https://dev.to/callstackengineers/code-splitting-in-react-native-applications-2bnh</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When it comes to React Native applications, the code for your application shares some aspects of the browser applications – web apps and we do have a well-established and thought-out solution for splitting functionality on the web which is called code splitting.&lt;/p&gt;

&lt;p&gt;Thinking about mobile apps, we usually have a mental model of a single runnable program that includes all the possible features. In fact, that’s how most of the mobile apps are architected and there’s a simple reason for that – it’s difficult to split functionality and deliver it later in a fully native mobile application. Especially if we are talking about cross-platform solutions for both iOS and Android.&lt;/p&gt;

&lt;p&gt;Why not bring this support to React Native? It turns out that it is in fact possible, but first, we need to understand it on a high level.&lt;/p&gt;

&lt;p&gt;In this article, I’ll focus on the idea of code splitting to introduce the concept and create a basic understanding of the technique.&lt;br&gt;
In the next one, we will go through technical details and implementation of code splitting using Webpack and &lt;a href="https://callstack.com/re-pack?utm_campaign=Re_Pack&amp;amp;utm_source=dev.to&amp;amp;utm_medium=re_pack_subpage&amp;amp;utm_content=re_pack_subpage_clutch_link"&gt;Re.Pack&lt;/a&gt; – a Webpack-based toolkit to build your React Native application with the full support of the Webpack ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does React Native run your code?
&lt;/h2&gt;

&lt;p&gt;Most of the time, developing React Native applications means writing the JavaScript (or TypeScript) code with the dependencies coming from repositories like NPM. However, the React Native runtime doesn’t understand our code in such form – it has no idea how to combine multiple files together or how to pull in the dependencies. It might even not understand our code at all due to unsupported syntax or type annotations. That’s why we need a tool to convert our code into a format that can be executed by React Native. This format is called a bundle, and the tool to create it – a bundler.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fczDkfXu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xqzt3ej8u3ql5rzsowj0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fczDkfXu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xqzt3ej8u3ql5rzsowj0.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;bundler&lt;/strong&gt; takes your source code, any dependencies and external libraries as well as static assets you use; transforms them, optimizes them and packs them together into a runnable bundle.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is code splitting?
&lt;/h2&gt;

&lt;p&gt;Code splitting is a technique that allows developers to create multiple bundle files instead of just one. By default, all your input files (source code, dependencies and assets) are combined into a single file. With code splitting, they are split into multiple ones.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--k_3kHJlB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qumyhktd8ehq3f7kza9b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k_3kHJlB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qumyhktd8ehq3f7kza9b.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We call each of the output files a chunk, while the main chunk (also known as entry chunk) can be referred to as a bundle.&lt;/p&gt;

&lt;p&gt;The bundle is still used as an entry point to the application, so React Native will execute it first, then it will load additional chunks on-demand.&lt;/p&gt;

&lt;p&gt;Code splitting is a technique to produce multiple output files which, as a whole, contains all your application’s functionality, but allows them to be loaded later on demand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code splitting in React Native apps – use cases
&lt;/h2&gt;

&lt;p&gt;Ultimately, it’s up to you to decide if your React Native application would benefit from code splitting, but there are some categories of applications that are good candidates for code splitting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Underperforming application
&lt;/h3&gt;

&lt;p&gt;Code splitting is a viable candidate for any kind of application, which has performance issues, especially in the startup area. Moving the code from the bundle to the additional chunk is a deferral technique. If used correctly, your React Native application will load only the necessary pieces of the code and postpone the load of others, which can help improve startup performance (TTR/TTI).&lt;/p&gt;

&lt;h3&gt;
  
  
  Modular applications
&lt;/h3&gt;

&lt;p&gt;Applications that expose different functionalities or different UIs based on user’s details are a great example of apps that would greatly benefit from code splitting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nyJYK4FM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/alks7co5tg98lxfu32cm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nyJYK4FM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/alks7co5tg98lxfu32cm.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let’s take an e-learning application for instance. With code splitting, it’s possible to separate a student’s and a teacher’s functionalities, so the application loads either of them, while decreasing the initial download size student or teacher would have to download and improving startup performance by loading only relevant code.&lt;/p&gt;

&lt;p&gt;Another examples of applications worth mentioning would be:&lt;/p&gt;

&lt;p&gt;an automotive application, which gives the user features based on their subscription plan&lt;br&gt;
a word processing application that provides language-specific functionalities. Each language can have a dedicated chunk loaded on-demand.&lt;/p&gt;

&lt;h3&gt;
  
  
  Super apps / Mini app stores
&lt;/h3&gt;

&lt;p&gt;Another two groups of applications where code splitting plays a huge role are so-called super apps and applications with mini app stores. Both super apps and mini apps stores are applications built from smaller, dedicated mini apps.&lt;/p&gt;

&lt;p&gt;Instead of having multiple applications on the App Store and Google Play you can combine them into a single one while streamlining the development and simplifying management.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GyhU-X6O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/senqpt4q0xum3a5o0d4i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GyhU-X6O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/senqpt4q0xum3a5o0d4i.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can think of &lt;strong&gt;super apps&lt;/strong&gt; as all-in-one mobile experiences – a closed ecosystem on many smaller apps.&lt;/p&gt;

&lt;p&gt;WeChat and Alipay are great examples of super-apps used by millions. With code splitting it’s possible to achieve it with React Native.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to introduce code splitting into React Native applications?
&lt;/h2&gt;

&lt;p&gt;Code splitting and the examples shown above are nothing new in Web development thanks to Webpack – a bundler for modern JavaScript applications. Due to its widespread adoption and rich feature set, we (at Callstack) decided to bring support for bundling React Native applications to Webpack.&lt;/p&gt;

&lt;p&gt;And this is how we’ve built Re.Pack – a toolkit that allows you to use Webpack and its code splitting functionality to bundle React Native apps.&lt;/p&gt;

&lt;p&gt;In the next article, we’ll take a closer look at how &lt;a href="https://callstack.com/re-pack?utm_campaign=Re_Pack&amp;amp;utm_source=dev.to&amp;amp;utm_medium=re_pack_subpage&amp;amp;utm_content=re_pack_subpage_clutch_link"&gt;Re.Pack&lt;/a&gt; can help us build React Native applications and leverage code splitting.&lt;/p&gt;

&lt;p&gt;Stay tuned!&lt;/p&gt;

</description>
      <category>webpack</category>
      <category>react</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>Technical Guide, Part 1: Compiling Hermes for Apple Platforms</title>
      <dc:creator>Callstack Engineers</dc:creator>
      <pubDate>Fri, 04 Jun 2021 14:19:38 +0000</pubDate>
      <link>https://dev.to/callstackengineers/technical-guide-part-1-compiling-hermes-for-apple-platforms-pea</link>
      <guid>https://dev.to/callstackengineers/technical-guide-part-1-compiling-hermes-for-apple-platforms-pea</guid>
      <description>&lt;p&gt;Months of our intense work with teams at Facebook and Microsoft resulted in bringing Hermes to iOS. We are happy to share the details of the process in a series of articles. This article is the third in the series and the first to focus on the technical journey:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://callstack.com/blog/bringing-hermes-to-ios-in-react-native/?utm_campaign=Hermes_MB&amp;amp;utm_source=dev.to&amp;amp;utm_medium=article&amp;amp;utm_content=article_distribution_dev.to"&gt;Bringing Hermes to iOS in React Native 0.64&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://callstack.com/blog/hermes-performance-on-ios/?utm_campaign=Hermes_MB&amp;amp;utm_source=dev.to&amp;amp;utm_medium=article&amp;amp;utm_content=hermes_performance_on_ios"&gt;Hermes Performance on iOS: How it Compares with JSC&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Technical Guide, Part 1: Compiling Hermes Engine for Apple Platforms (you are here)&lt;/li&gt;
&lt;li&gt;Technical Guide, Part 2: Integrating Hermes with React Native&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You are going to find out how we brought Hermes to iOS and how you can implement it yourself. We provide a detailed guide to Hermes implementation based on the actual work done. So, if you want to learn more about how different core pieces play together, keep reading!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nTIT_iTR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://static.callstack.com/wp/2021/04/12154852/hermes-illustrations-new_graf2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nTIT_iTR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://static.callstack.com/wp/2021/04/12154852/hermes-illustrations-new_graf2.png" alt="Compiling Hermes for Apple Platforms"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Compiling Hermes for Apple platforms
&lt;/h2&gt;

&lt;p&gt;Before we talk about &lt;a href="https://callstack.com/blog/bringing-hermes-to-ios-in-react-native/?utm_campaign=Hermes_MB&amp;amp;utm_source=dev.to&amp;amp;utm_medium=article&amp;amp;utm_content=article_distribution_dev.to"&gt;bringing Hermes to React Native on iOS&lt;/a&gt;, we actually need to compile it for Apple platforms. Hermes is written in C++ and compiled with cmake to existing platforms, so at a glance, it sounds like fun!&lt;/p&gt;

&lt;p&gt;Just to be on the safe side, let me explain that C++ is one of these cross-platform languages that can run literally everywhere. For example, you can write native modules in C++ for Android and on iOS (hey, the Objective-C is not just similar in its name). Thanks to that, seeing a task of compiling Hermes on Apple devices didn’t sound that scary when I first started playing around that topic.&lt;/p&gt;

&lt;p&gt;Thankfully, I didn’t have to start from the middle of nowhere (but I have to admit that playing around with cmake in general was quite an experience!). Folks at Microsoft have been working on bringing Hermes to Mac for their React Native macOS project. The work was done primarily by Eloy Durán (&lt;a href="https://twitter.com/alloy"&gt;@alloy&lt;/a&gt;), who sent a &lt;a href="https://github.com/facebook/hermes/pull/285"&gt;PR to Hermes&lt;/a&gt; with the base for my work.&lt;/p&gt;

&lt;p&gt;On a high level, this PR enables cmake to package Hermes in a dynamic library so that it can be used on a macOS platform. To make the integration with Apple ecosystem smoother, the PR adds a special Podspec so that you don’t have to manually import a framework file to your project. You can let CocoaPods do that magic for you instead.&lt;/p&gt;

&lt;p&gt;At this point, I was amazed by the comprehensiveness of cmake and the number of out-of-the-box features it provides. If you look at the changes in the aforementioned PR, they’re all related to the build system. It’s mind blowing to see that such an advanced project like a JavaScript engine can be run on macOS by just flipping a few flags, i.e. without changing the business logic of the engine itself.&lt;/p&gt;

&lt;p&gt;That’s good for me and all of you planning to work on C++ bits in the future! With that in mind, let’s move onto the iOS part.&lt;/p&gt;

&lt;h3&gt;
  
  
  On the way to iOS
&lt;/h3&gt;

&lt;p&gt;Having Hermes running on macOS was a good indicator that it might work on iOS as well. In case you want a quick version – &lt;a href="https://github.com/facebook/hermes/pull/332"&gt;here’s my PR with all the changes&lt;/a&gt;. If you’re curious about all the steps and a bit of technical explanations, carry on. &lt;/p&gt;

&lt;h4&gt;
  
  
  #1
&lt;/h4&gt;

&lt;p&gt;First thing I had to do was to tell cmake that it is no longer building Hermes for macOS, but for iOS. This can be achieved by setting a special variable &lt;em&gt;CMAKE_OSX_SYSROOT&lt;/em&gt; to configure the build pipeline to target specific SDK.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;set(CMAKE_OSX_SYSROOT ${HERMES_APPLE_TARGET_PLATFORM})&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I ended up going straight with a variable. We will need to build Hermes for every platform and architecture separately, which means building it a couple of times. Having a variable definitely helps – we can change its value depending on what we are targeting.&lt;/p&gt;

&lt;p&gt;The list of all platforms and architectures should be aligned with what React Native supports right now – otherwise, developers may run into issues on certain devices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here’s a breakdown of the platforms together with their architectures.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hpOgbzdc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://static.callstack.com/wp/2021/04/12165904/hermes-illustrations-new_table-768x327.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hpOgbzdc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://static.callstack.com/wp/2021/04/12165904/hermes-illustrations-new_table-768x327.png" alt="Graph showing platforms and their architectures"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  #2
&lt;/h4&gt;

&lt;p&gt;Another important thing was to tell cmake where to actually output generated files for every platform. &lt;/p&gt;

&lt;p&gt;By default, the library would be placed under a &lt;em&gt;Library/Frameworks/hermes.framework&lt;/em&gt; path within a build folder. Unfortunately, that would result in one build process overwriting the artifacts from the previous one.&lt;/p&gt;

&lt;p&gt;Since I wanted to keep the artifacts for every platform, I ended up tweaking the location where the files are placed:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;install(DIRECTORY ${DSYM_PATH} DESTINATION&lt;br&gt;
Library/Frameworks/${HERMES_APPLE_TARGET_PLATFORM})&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;As a result, the files would be now placed under &lt;em&gt;Library/Frameworks/iphonesimulator&lt;/em&gt; or &lt;em&gt;Library/Frameworks/iphoneos&lt;/em&gt;, depending on whether we’re building for a device or a simulator.&lt;/p&gt;

&lt;h4&gt;
  
  
  #3
&lt;/h4&gt;

&lt;p&gt;Now that the platform part was sorted, it was time to look at the architectures. The idea was to precompile Hermes in all possible configurations so that you don’t have to run it from source. That would be not only quite a time consuming process, but also prone to many errors, due to different configurations of our development machines. &lt;/p&gt;

&lt;p&gt;To do so, for each invocation of cmake, I ended up setting &lt;em&gt;CMAKE_OSX_ARCHITECTURES&lt;/em&gt; with the right value for every platform. Looking at the table I have shared just a few paragraphs earlier, that would be &lt;em&gt;“armv7;armv7s;arm64”&lt;/em&gt; for iPhone and &lt;em&gt;“x86_64;i386”&lt;/em&gt; for iPhone Simulator.&lt;/p&gt;

&lt;p&gt;Since that variable can be passed as a command line argument straight to &lt;em&gt;cmake&lt;/em&gt;, there is no custom code that I had to do to make it work.&lt;/p&gt;

&lt;h4&gt;
  
  
  #4
&lt;/h4&gt;

&lt;p&gt;The last thing to set was the deployment target – the version that we are targeting and is the minimum supported by Hermes. Again, that one is supported by cmake out of the box, so no changes here.&lt;/p&gt;

&lt;p&gt;The value of &lt;em&gt;CMAKE_OSX_DEPLOYMENT_TARGET&lt;/em&gt; was set equally to “10.0” for both simulator and the device.&lt;/p&gt;

&lt;h4&gt;
  
  
  build_apple_framework
&lt;/h4&gt;

&lt;p&gt;After testing the combinations a few times, I packaged them in a helper Bash function, called &lt;a href="https://github.com/facebook/hermes/pull/332/files#diff-fd14cc61bbe3b438fac38e3127d158db690bcbfc0f6539ac7c31ba64fb941ee0R45"&gt;&lt;em&gt;build_apple_framework&lt;/em&gt;&lt;/a&gt;, that takes these settings and tells CMake what to do. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;build_apple_framework "iphoneos" "armv7;armv7s;arm64" "10.0"&lt;br&gt;
build_apple_framework "iphonesimulator" "x86_64;i386" "10.0"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Thanks to that, it becomes trivial to control what platforms and architectures Hermes supports on iOS.&lt;/p&gt;

&lt;p&gt;Bonus points: it can be used to build macOS version too, so I went ahead and updated &lt;a href="https://twitter.com/alloy"&gt;@alloy&lt;/a&gt; part too:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;build_apple_framework "macosx" "x86_64" "10.0"&lt;/code&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  hermes.framework files
&lt;/h4&gt;

&lt;p&gt;After building Hermes with CMake for all the combinations, I ended up with two hermes.framework files: for iPhone supporting &lt;em&gt;armv7, armv7s and arm64&lt;/em&gt; as well as for iPhone Simulator supporting &lt;em&gt;x86_64 and i386&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;It would be a poor developer experience if you had to change a &lt;em&gt;hermes.framework&lt;/em&gt; in your project depending on whether you run on a device or a simulator. It would definitely hinder your work if you had to manually replace the library in your project.&lt;/p&gt;

&lt;p&gt;Thankfully, there are &lt;em&gt;universal frameworks&lt;/em&gt;, in other words – frameworks that support more than a single platform. Simply put – it’s a way to combine two &lt;em&gt;hermes.framework&lt;/em&gt; into a single one!&lt;/p&gt;

&lt;p&gt;You can create one programmatically with a &lt;em&gt;lipo&lt;/em&gt; – a tool to create multi-architectural files. To generate a universal framework file, the invocation would look as follows:&lt;/p&gt;

&lt;p&gt;lipo -create -output&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Library/Frameworks/iphoneos/hermes.framework/hermes&lt;br&gt;
Library/Frameworks/iphoneos/hermes.framework/hermes&lt;br&gt;
Library/Frameworks/iphonesimulator/hermes.framework/hermes&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To speed things up, I decided to merge all additional architectures into the iPhone binary. The first argument to &lt;em&gt;lipo&lt;/em&gt; is the destination, the following ones are input binaries that should be combined together.&lt;/p&gt;

&lt;p&gt;Just like before, I moved the logic into a Bash function, called &lt;a href="https://github.com/facebook/hermes/pull/332/files#diff-fd14cc61bbe3b438fac38e3127d158db690bcbfc0f6539ac7c31ba64fb941ee0R59"&gt;&lt;em&gt;create_universal_framework&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;create_universal_framework "iphoneos" "iphonesimulator"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Again, such an approach allows us to easily control the contents of the final hermes.framework file.&lt;/p&gt;

&lt;h4&gt;
  
  
  Last but not least
&lt;/h4&gt;

&lt;p&gt;The last piece was to update the Hermes.podspec created by @alloy to add iOS support.&lt;/p&gt;

&lt;p&gt;That required &lt;a href="https://github.com/facebook/hermes/pull/332/files#diff-423a7fb98745ae2cebb93241df2785476007e731ff755dd7bee844b4afcfcd51R29-R30"&gt;changing &lt;em&gt;spec.vendored_frameworks&lt;/em&gt; to &lt;em&gt;spec.osx.vendored_frameworks&lt;/em&gt; and &lt;em&gt;spec.ios.vendored_frameworks&lt;/em&gt;&lt;/a&gt; to tell CocoaPods that this package contains frameworks for both macOS as well as iOS (note that macOS and iOS binaries can’t be merged into a single universal framework – they are separate).&lt;/p&gt;

&lt;p&gt;In other words, replacing this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;spec.vendored_frameworks = "destroot/Library/Frameworks/hermes.framework"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;with:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;spec.ios.vendored_frameworks = "destroot/Library/Frameworks/iphoneos/hermes.framework"&lt;br&gt;
spec.osx.vendored_frameworks = "destroot/Library/Frameworks/macosx/hermes.framework"&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Try Hermes yourself
&lt;/h2&gt;

&lt;p&gt;The process of doing CMake reverse engineering took me three weeks, but it was worth it. I have learned a lot about build tools and this knowledge will be very useful in the future.&lt;/p&gt;

&lt;p&gt;You should definitely clone Hermes and play around with it. Follow our Hermes implementation guide and test it yourself. It’s quite easy to get started and working on a JavaScript engine can get really rewarding!&lt;/p&gt;

&lt;p&gt;If you want to learn more about Hermes, check our podcast: &lt;a href="https://callstack.com/podcasts/react-native-0-64-with-hermes-for-ios-ep-5?utm_campaign=Hermes_MB&amp;amp;utm_source=dev.to&amp;amp;utm_medium=article&amp;amp;utm_content=hermes_podcast"&gt;React Native 0.64 with Hermes for iOS&lt;/a&gt;. My guests, Microsoft and Facebook engineers, discuss the engine in detail!&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.youtube.com/watch?v=lbdIKZrOUMc"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KNplARtI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/http://img.youtube.com/vi/lbdIKZrOUMc/0.jpg" alt="The React Native Show Podcast Episode 5 React Native 0.64 with Hermes for iOS"&gt;&lt;/a&gt;&lt;br&gt;
Click on the image to watch the podcast video. &lt;/p&gt;

&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;p&gt;In the next part of this guide, “Integrating Hermes with React Native,” we will go through the steps that are needed to enable a custom engine to work with React Native, instead of the default JSC.&lt;/p&gt;

</description>
      <category>ios</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
