Expo QR code on Windows Subsystem for Linux (WSL2)
Tags: expo, reactnative, mobile, wsl
Published: 2024-03-05 19:47:02

**Prerequisites:**
- Windows 11/10
- WSL2
- NodeJS
- Admin Rights
- Up to Date Power Shell Version
- Dotenv

----

On one of the Top Secret project on [Devhat community](https://discord.gg/3gsMAEumEd) my team decided to work with [Expo](https://expo.dev/) to create our MVP, _Expo_ looks great but soon I figured out that it will make me suffer. ☠️

All my developer environment runs on _WSL_, _Windows Subsistem Linux 2_ to be precise, its been more than a year that I work with it, but soon I realize that its not that easy to run _Expo_ with _WSL_, there's no straight to the point tutorial nor a updated tutorial on internet on how to make it, but I wasn't comfortable to install Node, Git and god knows what else I would need to install on my _Windows_ just because of a single project, so I started a journey to find the golden way to run _Expo_ with _WSL_.

And thank god, I managed to make it work!

I'll divide this tutorial in two, the first part is to make _Expo_ works with _WSL_ thought the _QR code_ and, the second part, is [how to make it work with Android Virtual Device (AVD)](https://dev.to/alecell/expo-avd-android-virtual-device-on-windows-subsystem-for-linux-wsl2-4d8n), but keep in mind that this first step is required if you want to make it work with _AVD_.

----

### _WSL_ and _Expo_ _QR code_
First, get this script, available as [Gist](https://gist.github.com/Alecell/b6243922079e49e08963930bea318096#file-forward_wsl2_ports-ps1) as well, and move it to your root `C:`  **on your _Windows_**, the same place of your _Program Files_ and _Users_ folder, and name it `forward_wsl2_ports.ps1`. 

{% gist https://gist.github.com/Alecell/b6243922079e49e08963930bea318096 file=forward_wsl2_ports.ps1 %}

_Its worth to mention that this script is a slightly change of [this one](https://medium.com/weavik/react-native-expo-on-wsl2-aff04b1639f8), we needed to change it in order to make it work for people that has more than one IP on the `wsl hostname -I` command. Also if your want to understand what this script actually solves I strongly recommend you to read the article_

This script doesn't need any change if you use the default _Expo_ port `8081`, but if your _Expo_ run in another port you'll need to update the `line 6` of the script adding the desired port, for instance `$ports = @(8081,8089);`

#### Opening _WSL_ ports

Now on your **_Windows_**, open _Power Shell_ as administrator and **before run the command below** make sure that your _WSL_ is completely turned off, so close all _WSL_ terminals and editors such as VSCode and then `wsl --shutdown`.

With _WSL_ turned off you can run the command below:

```ps1
 powershell.exe -ExecutionPolicy Bypass -f C:\forward_wsl2_ports.ps1
```

If everything went right you'll see something like that

![power shell output after run the script](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x2zhyx7s2xmaa5osjghz.png)

This command opened the _WSL_ ports for the IP returned on the first step of the command `WSL IP 'the ip'`, in my case it opened just `8081` which is the default _Expo_ port, but if you added more IP's there it will open that other ports too. Then you can press any key and close this _Power Shell_ window.

#### Configuring the _WSL_ _Expo_ project

Go to your _WSL2_ and open your _Expo_ project or, if your don't have any, create a new one with `npx create-expo-app` and follow steps to create the project.

Open the project with your desired editor and lets add a new script on our `package.json` file, this script will be a specific one to run the _Expo_ project on through your _WSL_.

```js
"scripts": {
  /* other scripts */
  "start:wsl": "REACT_NATIVE_PACKAGER_HOSTNAME=$(node get_network_local_ip.js) expo start"
}
```

We'll need to add the `get_network_local_ip.js` file on the next step, but all that `package.json` command does is run the _JavaScript_ file to get your local internet IP address and then set it as the hostname for _Expo_ instead use the default one!

The project will work if you replace the `$(node get_network_local_ip.js)` with your local IP. To know your local IP you can go to, on _Windows 11_, `Start -> Network & Internet ->  Properties` and then look for `IPv4 address`.

So, if you're a solo developer its _"ok"_ if your script look like this

```
"start:wsl": "REACT_NATIVE_PACKAGER_HOSTNAME=19X.XXX.XX.XXX expo start"
```

But for teams this solution is not a good one, that's why we need the `get_network_local_ip.js` script!

All that script does is search for the IP of your active internet network, but its worth to mention that this is a updated version of the command showed on [Kendall article](https://medium.com/weavik/react-native-expo-on-wsl2-aff04b1639f8) as well.

Kendall's current solution in `package.json` to find the internet interface _IPv4_ is great, but it could lead to issues in scenarios where a different internet interface other than "Ethernet" is used or the _IPv4_ regex doesn't match 'IP Address'. Modifying `package.json` for these local-specific configurations would result in unnecessary changes in every _Merge Request_. To avoid this, I've implemented a separate `get_network_local_ip.js` script that leverages a `.env.local` file for local configurations, ensuring a more flexible and MR-friendly approach.

I also updated the regex to look for the IP, but this is a idiom specific issue, if you want you can read the explanation below.

> **Why did I update the IP regex:** I'm a Brazilian and so the original script `netsh.exe interface ip show address 'Ethernet' | grep 'IP Address' | sed -r 's/^.*IP Address:\\W*//'` don't work for me since my `netsh.exe` displays the interfaces in `pt-br` not `en-us` and that's a huge problem cause here "IP Address" becomes "Endereço IP", a word with a `unicode` character that's very hard to work with bash scripts and even harder with a script that is somewhere between _WSL_ and _Power Shell_. All my attempts to search for "Endereço IP" with `grep` were failures so, instead of replace the "IP Address:" section, on this updated script I look for the actual IP which was way easier. I also believe that this will work on many other idioms around the world, so its a more cross language solution.

Here's the updated command as a _JavaScript_ file, its also available on [this gist] (https://gist.github.com/Alecell/b6243922079e49e08963930bea318096#file-get_network_local_ip-js). Add it to the root of your project with the name `get_network_local_ip.js`

{% gist https://gist.github.com/Alecell/b6243922079e49e08963930bea318096 file=get_network_local_ip.js %}

You'll also need the `.env.local` file to define your local variables for your internet interface name and your regex to look for your _IPv4_ label.

{% gist https://gist.github.com/Alecell/b6243922079e49e08963930bea318096 file=.env.local %}

#### Your interface name and IP regex

On your `.env.local` you need to add the name of your internet interface and the regex to find your _IPv4_, here's how you can find it:

On _Windows 11_ go to `Start -> Network & Internet ->  Properties`, look for `IPv4 address` and save the IP for later.

Then open your **_WSL_ terminal** and run `netsh.exe interface ip show address`, it will return a bunch of network interfaces, in my case its **a lot of interfaces**, but in your case you can have only few, either way we just want one of them, the one that the _IP Address_ is the same as the IP we saved previously saved.

In my case `Ethernet 3` is the interface that has the same IP, so I can update that `LOCAL_CONNECTION_INTERFACE_NAME` environment variable with `Ethernet 3`.

![output of the conection interfaces on windows](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ljigkfm3hqzxokfcqkf3.png)

In your case it could be just `Ethernet`, `Ethernet 2` or even `WiFi`, all depends of how and which internet port you're using to connect your device on the internet.

Now, on the left of your IP is how your "IP Address" is called on your idiom and with that you'll need to get the most of the word on your idiom, avoiding `unicode` characters, to search for your IP later with the variable `LOCAL_CONNECTION_IPV4_SEARCH`. In my case for instance if add the whole "Endereço IP" will throw a error cause 'ç' is a `unicode` character, but if I search for `Endere` it finds the right label!

You can test if your chosen word works running

```bash
netsh.exe interface ip show address 'YOUR_INTERFACE_NAME' | grep -a 'YOUR_IPV4_SEARCH'
```

In my case it is

```bash
netsh.exe interface ip show address 'Ethernet 3' | grep -a 'Endere'
```

If it returns something like _"YOUR WORD: YOUR IP"_ it worked! In my case 

![output of the filter on the netsh.exe command](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1kqy28s9ffsveom4o1it.png)

Now we can add the value to the `LOCAL_CONNECTION_IPV4_SEARCH` variable, my `.env.local` is looking like this

```bash
LOCAL_CONNECTION_INTERFACE_NAME="Ethernet 3"
LOCAL_CONNECTION_IPV4_SEARCH="Endere"
```

Now test if your script is working, on the opened _Expo_ project run `node get_network_local_ip.js` and it should return your _IPv4_ 

![IP as return of the javascript script](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g3o0c5l9za6deebyb0zd.png)

If it returned your IP everything it setup! Now the only thing you need to do is check if your cellphone is connected to the same internet as your computer and then, on the _Expo_ project, run

```bash
npm run start:wsl
```

You can notice if everything went well if _Expo_ displays your IP as the _Metro_ connection instead of another one


![expo output your local ip as Metro connection](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1nkudw30425v8yorog8b.png)

Now you can download the _Expo_ App on your cellphone, scan the _QR code_ and it should work as expected! 🥹


![expo working on my own device](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r2fjxihw2f1bts0ooyow.jpg)

### _WSL_ and _Expo_ _AVD_ (Android Virtual Device)

For those who want to use _Expo_ through a virtual device the [tutorial continues here](https://dev.to/alecell/expo-avd-android-virtual-device-on-windows-subsystem-for-linux-wsl2-4d8n) on how to run _Expo_ on _WSL_ with a _Android Virtual Device_!

If this tutorial helped you please leave a comment or a reaction! 

Thank you for reading, see ya!