Part 1 – Converting react native app to react-native-web (react PWA) in monorepo architecture
Tags: react, reactnative, uncategorized, websites
Published: 2019-11-24 14:56:26

---
title: Part 1 – Converting react native app to react-native-web (react PWA) in monorepo architecture
published: true
date: 2019-07-28 18:18:33 UTC
tags: React,React-native,Uncategorized,Web Sites
canonical_url: https://ziatechblog.wordpress.com/2019/07/28/part-1-converting-react-native-app-to-react-native-web-react-pwa-in-monorepo-architecture/
---

### **TL;DR** :

This series is about my journey of **converting and existing react native app to render on web with same(90%+) code**, using the brilliant [react-native-web](https://github.com/necolas/react-native-web) project which[came out of twitter](https://twitter.com/necolas/status/913877194199359488?lang=en).

### Prerequisites:

This article assumes you already have some experience with `reactjs` and `react-native`, you know how to build mobile builds of a RN codebase, and have them run in a simulator.

### **Disclaimer:** 

I am mostly experienced in `Ruby on Rails` full stack development with mostly focus on backend and DevOps, i have worked on and off on different JS frameworks, but _I am not an expert(yet) in `babel` and `webpack` configurations etc_. So proceed with caution, and point out any improvements in the process in comments.

I am not yet sure how many parts this series will take. Also my work of conversion of this app is still WIP, so who knows what and where that work ends up. But i will share my journey anyway.

Also note,  we did not had any active android builds, so this series won’t be explaining steps involved with building android successfully. But you should be able to have them run in the similar way as i will explain for ios below.

_You can skip Credits and background section if you like and can jump to “_Let’s Just begin the actual stuff!_” section._

### Credits/Shoutouts:

Before we begin our journey, i wanted to give credits to a couple of people who helped a lot on this journey, first one is the [Bruno Lemos](https://dev.to/brunolemos), i got the `react-native monorepo setup` with initial `react-native-web` setup from [his excellent blog post](https://dev.to/brunolemos/tutorial-100-code-sharing-between-ios-android--web-using-react-native-web-andmonorepo-4pej). And other one is [Thomas Gladdines](https://github.com/seahorsepip), he was so kind to help me through email with all queries i had in the process.

## Background:

On a product i am working on, they have a **fully functional react-native app released in iOS app store** (_It did not had android builds and releases, we are planning on that as well but thats not the topic here)._ We had its RN version recently **upgraded from `56.x to 59.9`** , the app _IS_ on app store, but with not a lot of users just yet, as it is a startup still trying to get kick-started with their initial contracts and everything. Anyway.

_Suddenly one morning,_ we have an emergency meeting, and the project manager tells us that we have these X and Y clients whom we are going to partner with, and these are business critical deals. **And the issue is, they both need a web app instead of the mobile app, that too ASAP. And we need to port our react-native app to web version within a week or so,** knowing we are team of only two devs. Yup! Just like that.

And incidentally, both of us had not any experience of converting apps to web. So **I was tasked to do some R&D and provide a feasible plan for this conversion with minimum friction and time requirements.** So as per pressure from the business side, we had to choose something where we have minimum to none learning curve.

**In a perfect world** , we will just be putting our code through some code convertor which coverts our `react-native` app to `reactjs` web app. **But we don’t live in a perfect world, do we?** Turns out, react community is making great progress towards hybrid apps and PWAs but it is not yet quiet there, [ionic has its react beta out](https://ionicframework.com/blog/announcing-the-ionic-react-beta/), there is a project called [ReactXP](https://github.com/microsoft/reactxp) from microsoft and [expo is also working on web compatibility of its apps](https://www.google.com/search?client=opera&q=expo+react+web&sourceid=opera&ie=UTF-8&oe=UTF-8). It almost felt like we needed this conversion a couple of years too early.

So keeping in mind our short time notice and business criticality, we just decided to keep our learning curve low and not worrying too much about future and **to use [react-native-web,](https://github.com/necolas/react-native-web) which currently officially supports Rn 0.55, and we are on 0.59**, as we had saw some people mention they are successfully running RN-web on RN 0.59, some mentioned some hacks [like making `react-native-web` think its RN 0.55 when compiling for web](https://github.com/necolas/react-native-web/issues/1172#issuecomment-472196873). So we just decided to go with RN-web to get something running on web ASAP.

I had to do a few re-dos to make it all work, thats why i thought it worths to write about it in detail, so people are not stuck where i did stuck and had to re-setup everything in a hope it will work, kind of restart ![🙂](https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/1f642.png)

## Maintainability and future?

This is a tough question, there is active progress on RN web, although it doesn’t look very active as far as commits go, and its having hard time keeping up with latest RN versions, but as more and more people start using this, more and more people will collaborate and participate in its development, and we should see better future.

The monorepo architecture itself is quiet amazing and works flawlessly with `RN`(except the issues of linking), but only issue we can foresee with `react-native-web` is its active development. Its great to try out and get something running. But if you face too many issues and/or missing features you can’t live without, and you also happen to have lot of time to transition to `ionic` or `ReactXP` or anything like that, you can try those out. But as I mentioned, those are also not yet that mature, so good luck with that as well.

## Let’s Just begin the actual stuff!

Before starting, i should stress on importance of version control, just keep committing every small step which worked with proper commit messages, and you will save a lot of time.

Ok, here we go.

### Initial monorepo setup:

As i mentioned above, i am using the monorepo architecture to share code between mobile and web, and i followed [an excellent blog post](https://dev.to/brunolemos/tutorial-100-code-sharing-between-ios-android--web-using-react-native-web-andmonorepo-4pej) on the matter. There is a [boilerplate repo](https://github.com/brunolemos/react-native-web-monorepo) also linked in the article, which you can use. But i preferred to setup this whole thing from scratch as described in the post i linked, so have a better sense of understanding of whats actually going on. Turns out, there is a lot going on.

_BTW, there is an [interesting debate of `monorepo vs multi-repo` architecture,](https://medium.com/@mattklein123/monorepos-please-dont-e9a279be011b) we are not going that route. But it worths mentioning, when we are using something like RN-web, it makes most sense to have this architecture. Maybe not that much if we were just sharing the services and reducers etc among web and native react._

Ok, now we have our monorepo setup, with basic boilerplate running on both mobile and web. **Let’s start importing our existing mobile app to this architecture.** Before we do that, i must mention that you can try converting the existing app to monorepo setup in place, but that didn’t work for us, was taking too much time that we decided to just port it over.

### Little walkthrough of the monorepo setup

During the setup from above guide(which you have to do from there, i will not be doing that all again over here), you would have noticed we are using `yarn`, and its `workspaces` feature. We have a folder called `packages` on the root, it contains currently 3 sub-folder, each with their own `package.json` file. but important part is, all the packages will be installed in the `node_modules` folder at the root. Not in sub `node_modules` folders.

**Lets go through these packages/folders one by one:**

**1- `Components`:** This folder will hold generic components or the shared code so to speak, in this component we will have everything that we want to share. You can get creative with the naming if you like.

**2- `Mobile`:** As name suggests, this folder will hold our mobile specific code. And when working/building mobile we will be staying in this folder. This folder further has the usual folders we see in any react-native app, the `ios` `android` `src` folders etc. You should already know what are those and how we use them.

**3- `Web`:** This is where actual web magic happens. This is supposed to be focus of this article.

### Gotchas!

Just like there is no free lunch, there are a few issues I have came across. I am pasting first 3 straight from Bruno’s original article.

1. `react-native-web` supports most of the `react-native` API, but a few pieces are missing like `Alert`, `Modal`, `RefreshControl` and `WebView`
2. If you come across a dependency that doesn’t work well with the monorepo structure, you can add it to the [nohoist](https://github.com/devhubapp/devhub/blob/2f64088b84611f7458d3dd7933baf25ffb5196d9/package.json#L16-L18) list;
3. `react-native link` might not work well with monorepo projects without `nohoist`; to workaround this, use `nohoist` on `**/react-native` OR instead of installing the dependencies only using `yarn workspace mobile add xxx`, install them in the root directory as well: `yarn add xxx -W`. Now you can link it and then later remove it from the root `package.json`.  
_(So far what I have been doing is the second option from this. Which is to copy dependencies to root `packakeg.json`and later remove them from there.)_
4. Lookout for library versions when you copy the dependencies from existing app, they _WILL_ change and may jump to latest versions without you noticing if you don’t **properly lock them in** `package.json`, so i recommend you spend some time locking them properly and than making sure everything works in old app, before starting to port it.
5. Be prepared to have some details of the functionality of your mobile app to be compromised, at-least for short term. As odd as it sounds, its a reality I faced, some RN components are not even supported in RN-web, one of them is `Alert`, which we happen to use a lot, so we will need some patch(if we can find any) to make it work or we will have to use something else to achieve the same functionality.
6. Unless you decide to limit the width of your web app, `you will probably have to fix a lot of responsiveness issues`. And for some components/screens of your app. It may even feel like re-writing the view layer. As you can imagine the drastic changes for responsiveness.
7. I have not yet setup some proper `versioning script` like the one we were using in the old setup, but that might be a bit of problem for us. And we may need something custom for that, unless we can live without this and waste time every-time we need to release a new version.
8. Lastly, as of point 4, 5 and 6, you can already guess, this RN and RN-web combo will work best for new react apps aiming for PWA or hybrid results, so to speak. This doesn’t mean it doesn’t worth a shot when you are short on time and want something out on web from existing RN codebase.

## Importing existing app to this new setup

### Let’s start with dependencies

I decided to first have dependencies moved, installed, and `yarn.lock` file properly updated and than copy actual code. So i did that. I copied everything under `dependencies` and `devDependencies` sections in old `package.json`(except react and react-native, any any other duplicates), and moved it over to `packages/components/package.json` sections respectively. _(Note that I was not careful about the gotcha number 4 i mentioned above, that caused number of issues for us later on, so lookout for that)._ After i got everything installed and mobile app was still running fine(of-course, because we haven’t imported anything from these new dependencies), i made a new commit.

### Now import actual code

This particular step may sound like an easy thing, but it’s actually not. Believe me, I spent at-least one and a half of day to make it build for mobile in this new architecture! Yup…

To import old code, i will explain what strategy i took, and you can decide what works best for you. I decided to copy whole existing code to `components` package of the app, which is for the shared code. Idea was to first build the mobile successfully in this architecture, then try on web, and move what needs to be moved to mobile or web specific sub-packages.

So i just copied everything from my old src folder to `packages/components/src` and in our old setup, we had `App.js` outside of the `src`, i moved that inside of the `src` as well, and had to update some import paths in `App.js` but that’s fine. Now app should work? No, don’t forget linking and other `xcode` specific settings your dependencies may require.

### Linking libraries and `xcode` fixes for our app

_There might be a better way to do this than what i am going to describe by my experience._

As mentioned in point number 3 of the gotchas section, linking is a bit tricky. Before linking though, **if you use `cocoa pods`, please setup those. Even if you don’t, this might be a good time to use them. Install cocoa pods**. When it looks good, choose how would you like to link the libraries, as described in above mentioned section, for now, what i am doing is copying over all dependencies from `packages/components/package.json` to main `package.json`, yarn install and run `react-native link` from main directory. Then remove these dependencies from main package.json and yarn install. Last step, obviously, inside `ios` directory run `pod install`.

**I had some complications** , which turned out to be caused by something else, which i will explain in a minute, but on this stage, what i did was to _copy over my old `podfile` completely_. I mean if you have a `podfile`, it didn’t hurt to copy old one and just fix the references to the `node_modules` folder present in main directory of the repo.

**At this step, you can try and run your `.scworkspace` file of your project, clean the build have the `metro bundler` running in the background** (as described in the monorepo setup guide i linked command is something like: `yarn workspace mobile start`), and **let’s try building the app**. If you are lucky enough, your app will run, mine didn’t. It did built successfully, but it failed when loading files from metro bundler.

#### Strange `path` and `fs` errors

First i had **`bundling failed: Error: Unable to resolve module `path`...`** error, i blindly added a package named something path(you can google it up, i don’t remember, maybe it was named just path). Then i started seeing `bundling failed: Error: While trying to resolve module `fs` from file...` and `node_modules/fs/package.json` was successfully found. However, this package itself specifies a `main` module field that could not be resolved` thats when i thought maybe, **it is something wrong with my config** , not my dependencies, because i have all my dev and other dependencies installed same as in previous app. So it is not the dependencies i need but something else. What is turned out to be? _I missed to copy babel presets from old `babel.config.js` to new one in mobile package. **And that solved both of these issues.** _

That was the part where I wasted a lot of my time. after this, i retried the build, low and behold! another error of-course ![😀](https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/1f600.png)

#### `react-native native module cannot be null` errors

This error was appearing after loading from metro bundler, turns out, **it is complaining about missing proper linking**. As some libraries don’t just require you to run `react-native link` they sometimes involve manual steps as well, like the `react-native-permissions` package. So i had two options at this stage:

1. Go through all my dependencies readme, and make sure we have everything setup as needed.
2. Match the old `.xcworkspace` file libraries and linked section and make sure we have everything matching up.

For the shortage of time, i took route 2, i don’t recommend it, especially if you have android builds active as well. This took me some time to make sure we have everything we need. And after a few rounds of failure with similar errors, i was able to run the app.

**NOTE:** _This is the section i am almost sure about that this would have some better way of doing this than the above mentioned two, definitely better than the approach I took. Comment if you can suggest anything, and i will add it in the list for readers._

### Boom! Mobile app is running in monorepo setup!

There might be some other bits according to your setup, but that was it for me and i had my mobile build running! Finally!

**PS:** As i mentioned, i had not properly locked my dependencies, i had some issues in the app at this point, but it was working, and our only goal was to have a web version ready ASAP. So we just took note of those issues and moved on.

![download](https://ziatechblog.files.wordpress.com/2019/07/download.jpeg)

Well, at-least for part one. We have our mobile app running in this architecture. We can go from here in the next part and actually start porting for web app.

Please share your experiences and anything you want to add/fix in the article.

Till next time, TC.

[Part 2 can be found here.](https://ziatechblog.wordpress.com/2019/08/18/part-2-converting-react-native-app-to-react-native-web-react-pwa-in-monorepo-architecture/)