Mobile Preview - Part 1 - Preview a react native application in the browser

Corneflex
7 min readJul 10, 2023

--

I’m working on a low-code / no-code platform which generates React Native applications.

One of our challenge was to create a live preview of the application visible on the webbrowser (like codesandbox, snackexpo, stackblitz,…) or directly on a device. Any changes made on the no-code editor should be reflected instantly in the preview. The preview must provide a faithful representation of the final generated application (fully interactive with the same UI).

There are several methods to tackle this issue, and the present solution fells short in terms of performance and optimisation compared to CodeSandbox, SnackExpo, and StackBlitz. Nevertheless, it will provide insights into the challenges posed by such a project.

Implementation details are explained in the 2nd article.

First take a look at all the possibilities

Displaying the app in the browser

The first problem we faced was figuring out how to display a React Native application in a web browser.

  • One solution is to stream a simulator inside the browser. For that we could use Appetize.io. It is a web-based platform that allows users to emulate, stream, and test mobile applications and websites inside the browser.
  • Another solution is to make the application web compatible with React Native for web, bundle it and display it directly on the browser, but it might lose some native features and the look might not be 100% accurate.

Showing the application in the browser is one thing, but rebuilding and modifying it in real time is another. This brings us to the next point

Live reloading

Developers are accustomed to the concept of live reloading, where development tools provide it for free (ex: Webpack for web, and Metro for react native).

It works as follows: a watcher service checks the modified files, Webpack or Metro transpile and bundle the modified files, and refresh the web page or the application with the new bundle.

(For information: Webpack contains some optimisations like Hot Module Replacement that exchanges, adds, or removes modules while an application is running, without a full reload. This can significantly speed up development in a few ways).

In our context, we are not on the local computer of the developpers, and we need to find a solution to build, transpile and bundle the app inside the browser or a within a VM or a docker container in the backend.

Native preview

If we choose to display the native application in a simulator with appetize, we could use a containerised expo server hosted on our cloud platform. Expo application simplify greatly the process by providing an the expo go client application already build for IOS and Android.

The Expo server employs Metro, a JavaScript bundler, which wraps our application into a compact bundle. The streamlined version of our application is then dispatched directly to the Expo Go client.

The Expo Go client is a native application that allows us to open and run projects created with Expo without needing to go through the build process ourselves. It’s conveniently pre-installed on the Appetize simulator to further streamline the development process.

https://docs.expo.dev/get-started/expo-go/

Expo App

Expo with Appetize

In the case we would display the web counterpart of React Native app, we can orient our research on web development tools, and remove simulators of the equation.

Web preview

Bundle the App directly in the browser

Not long ago before webassembly changes the game, working in the browser has some limitation as we are not able to run Node application like webpack directly inside it.

If we take codesandbox has an example, when you’re working in a sandbox, CodeSandbox uses a bundler that was specifically created for the browser (Nice article about the subject). This is similar to how bundlers like Webpack or Parcel work in a local development environment.

The bundler fetches dependencies from the npm registry and bundles them along with your code. It supports many features you’d expect from a module bundler, such as support for ES modules, CommonJS, and dynamic imports. The bundler is also capable of handling different file types like JavaScript, TypeScript, CSS, and even image files.

The process happens in real-time as you code, which allows you to instantly see the results of your work. The output is served in an iframe, which provides a measure of isolation from the rest of the CodeSandbox application.

I found a similar approach on Snack Expo, and the next diagram shows some of the implementation details. Expo Snack is open-source platform under MIT and BSD licences for running React Native apps in the browser.

Containerized nodejs

For more complex applications, code sandbox provides container-based sandboxes and MicroVm (Amazon Firecracker) which support running server-side Node.js code. If you want some details of their implementation look at this post which explains some of the implementation details and how they arrived to clone micro vm snapshot so fast.

https://codesandbox.io/blog/how-we-clone-a-running-vm-in-2-seconds.

This solution permits to run webpack directly in the container. It gives a dedicated server to the client as if we work in a local development environment (live reloading, instant refresh, …)

Webassembly and webcontainers

Thanks to webassembly, Stackblitz proposes a new solution Webcontainers, which permits to run node.js directly inside the browser,

WebContainers are a browser-based runtime for executing Node.js applications and operating system commands, entirely inside your browser tab. Apps that previously required cloud VMs to execute user code, in WebContainers can run entirely client-side with a number of benefits over the legacy cloud VM.

https://webcontainers.io/guides/introduction

The advantage of the webcontainer is that calculations are performed directly on the client machine. There’s no longer a need for expensive infrastructure.

Dynamic rendering — micro front end & plugin architecture

Previous solutions considered that we had to transpile / bundle the code, but in the case of our no-code application, we have implemented a React Native rendering engine. This engine can dynamically render the application at runtime from a JSON format that describes the entire application architecture (navigation, screens, components hierarchy, bindings, services,…)

For adding new functionalities to the engine without recompiling the whole app, we adopted a plugin architecture. We use module federation feature, which permits to bundle part of an application and load them dynamically at runtime. If you want to get more information and how to implement a such architecture, I let you see my previous article.

The inconvenience of the dynamic rendering, is that we should give a particular attention to memory consomption and performance as everything is interpreted at runtime.

But this weakness is also the force of this solution. The runtime interpretation simplifies considerably the application preview problematic. We do not need to bundle the code as everything is dynamically interpreted. So no need to create a custom bundler nor to create a dedicated VM / container for each client.

Our Implementation of React Native Preview

For information, at the moment we decided our implementation, webcontainers were still in alpha and we were not aware about Firecracker, finally Google Cloud run does not totally fit our needs as it is more appropriate for stateless applications that can quickly start and stop.

Nowadays we would implement it differently, or use directly CodeSandbox or Stackblitz’s webcontainers. They’ve made a splendid work, they really rock and change the face of development and collaboration Thank you :)

Now it’s time to explain you what we chose and how we implemented it.

The decision was to affect a dedicated expo server per user, which will transpile the code, serve and refresh the preview. We used React Native for Web to make it compatible for web and be able to display it directly in the browser.

For that we use Kubertenes and its API for managing resources dynamically, called from a nodejs service. Resources in the pool are dynamically allocated and deallocated as per demand, without the need to frequently create or destroy them. This improves performance and resource utilisation, especially for resources that are expensive or time-consuming to create.

Unlike Knative, which optimises resource consumption by scaling down to zero during periods of non-use, this strategy might consume more resources as it maintains a pool of readily available resources. However, it effectively eliminates the ‘cold start’ issue, which is the delay that occurs when new resources need to be initialized after a period of inactivity. This ensures that the service responds promptly to requests, offering a more consistent performance.

This diagram shows the kubernetes architecture that we put in place

I’ve created a repository which exposes this architecture. I will explain it in the 2nd part of this post:

https://medium.com/@CorneflexSteve/managing-a-pool-of-pods-dynamically-inside-kubernetes-f937a62f7aca

https://github.com/corneflex/preview

--

--