Developing on Expo using VSCode and Docker
Tags: reactnative, docker, vscode, development
Published: 2021-08-07 12:40:45

I am a productivity freak. I want my dev environments to be the best and most predictable, so that I can share them with my coworkers easily. You can read some of the posts around using VSCode and Docker based development environments I have written earlier on my blog ( https://blog.mandraketech.in ). In all the previous cases, I have been working with the server side, and hence NodeJS is the primary target.

I am also a fan of creating Remote Container based development environments. It allows me to:
- have multiple environments running without killing the CPU on my old Intel i3 processor
- allows me to run the Docker host on Digital Ocean / AWS EC2, and hence share environments with my peers

So, I started from scratch, building up on my experience with the NodeJS and VSCode based environments.

Let's create a directory for ourselves, and get started. The name of the directory should be a name that you would want to see in the Docker Desktop dashboard, and helps you identify what you are running. For example: `hello-app-dev`

You can find all the code from this post at  [https://github.com/navneetkarnani/vscode-expo-starter](https://github.com/navneetkarnani/vscode-expo-starter) 

## Creating the Dockerfile 

The first stage is to create a Docker image, that will have all the tools we want to run. In this case, we want an image that has ReactNative, Expo CLI, NodeJS, Typescript and ESLint preinstalled. So, I started with Node 16, and built this:

Create a file called `Dockerfile`, with the below contents:
```
# [Choice] Node.js version: 16, 14, 12
FROM node:16

# init for VS Code
RUN mkdir -p /root/workspace /root/.vscode-server/extensions 

# Install eslint typescript expo
RUN npm install -g npm@latest
RUN npm install -g eslint typescript expo-cli @expo/ngrok@^4.1.0
RUN node --version && npm --version

CMD /bin/sh -c "while sleep 86000; do :; done"
```

You will notice that I have `@expo/ngrok` installed too. This is because we want to start expo in `tunnel` mode directly from the commandline, instead of having to launch it in LAN mode and then switch. So, ignore it for now, you will see it in action later.

## Creating the docker-compose file

`docker compose` enables us to define a full environment, with the storage/volumes and any other customisations necessary. Since my intention is to build a fully remote enabled environment, we will store all our code in a docker volume. That way, there are no references to the host. 

Create a file called `docker-compose.yml`, with the contents below:
```
services:
  expo-dev:
    build:
      dockerfile: ./Dockerfile
    volumes:
      - code:/root/workspace
volumes:
  code: {}
```

with this, we are in a position to run the command:
`docker compose up -d`

to see the environment working. But we are not done yet. Hold on So make sure you clean it up: `docker compose down --remove-orphans -v`

## Remote container on VS Code using DevContainer magic

Tough not mandatory reading, if you are interested in a detailed understanding of the VSCode feature, read up here: https://code.visualstudio.com/docs/remote/create-dev-container

Lets create a file called `.devcontainer.json`, with the following contents:
```
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.191.0/containers/docker-existing-docker-compose
// If you want to run as a non-root user in the container, see .devcontainer/docker-compose.yml.
{
	"name": "expo-dev",
	"dockerComposeFile": [
		"docker-compose.yml"
	],
	"service": "expo-dev",
	"workspaceFolder": "/root/workspace",

	// Use 'forwardPorts' to make a list of ports inside the container available locally.
	"forwardPorts": [ 19000, 19001, 19002 ],
}
```
For a more detailed configuration, with more pre-configuration, refer to the code in the [Git repo] (https://github.com/navneetkarnani/vscode-expo-starter)

One point I want to call out here though, the use of "forwardPorts" in devcontainer.json instead of the "ports" in `docker-compose.yml`. 

The purpose of `ports` in the `docker-compose.yml` is to bind a port to the host where the container is running. Whereas, the `forwardPorts` mechanism uses the VS Code infrastructure to forward the traffic. 

The difference is that the container is not locking the specified ports on the host. This allows multiple environments to run side-by-side. Plus, does not need opening firewall ports when using a remote Docker host.

## Starting the container with VS Code

We are now ready to go. Make sure you have VS Code installed on your machine, and the [`Remote - Containers`](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)  extention installed. You can also search for `ms-vscode-remote.remote-containers` extension.

Now, open the folder containing the above files in VS Code. Either from the terminal, by typing `code .` or just opening the folder, as you would otherwise do.

VS Code will prompt you that it found a `Dev Container configuration file`. Click on the `Reopen in Container`.
![Screenshot 2021-08-07 at 5.33.44 PM.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1628337842861/ZSm5z2aju.png)

Or, alternatively, you can start the `Command Palette` using the `F1` key, and search for `Reopen in Container`. If you make changes to any of the above files, you can also do a `Rebuild and reopen in Container`.

## Getting started with Expo

As you may have noticed, the `code` volume is mounted to the `/root/workspace` folder. So, you need to open that folder in VS Code. Given the `.devcontainer.json` file, it should be open by default.

Start the terminal, and make sure you are in the same folder.

We will generate a "starter" project, for testing, called `hello`.

Run `expo init hello` in the terminal. Select a template of your choice ( I prefer the typescript ones ). And wait for the process to complete.

## Running Expo, the final leg

Before running the app, make sure you have the [`Expo Go` application](https://expo.dev/client) installed on your development phone. 

On the terminal, switch to the `hello` folder, and run `expo start --tunnel`. The browser will open up with the packager console, and the `Tunnel` mode selected. If not, then something is not right. Message me and we will try to figure it out.

You will see a QR code in the terminal, as well as on the browser. Scan it, and it should open using Expo Go. 

## Summarizing

What did we achieve in this post:

With only docker cli as the local component on a machine, we are able to build a development environment for Expo. This environment can run on machines with Docker Desktop, or where the Docker host is running remote. Loads of options. This is even AWS Fargate friendly.

VS Code documentation on using [Remote Docker host] ( https://code.visualstudio.com/docs/remote/containers-advanced#_developing-inside-a-container-on-a-remote-docker-host )

[Digital Ocean Running remote Docker host] ( https://www.digitalocean.com/community/tutorials/how-to-use-a-remote-docker-server-to-speed-up-your-workflow )

[AWS doc on running docker in EC2] ( https://docs.aws.amazon.com/AmazonECS/latest/developerguide/docker-basics.html )


This blog was originally published by Navneet Karnani ( navneet@mandraketech.in ) on his blog at:  [https://blog.mandraketech.in/developing-on-expo-with-ios-using-vscode-and-docker](https://blog.mandraketech.in/developing-on-expo-with-ios-using-vscode-and-docker)