[DevContainer] Developing on Expo using VSCode and Docker

Developing multiplatform mobile apps in a portable dev environment

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 ( 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

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:

      dockerfile: ./Dockerfile
      - code:/root/workspace
  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: code.visualstudio.com/docs/remote/create-de..

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": [
    "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] (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 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

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 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.


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] ( code.visualstudio.com/docs/remote/container.. )

[Digital Ocean Running remote Docker host] ( digitalocean.com/community/tutorials/how-to.. )

[AWS doc on running docker in EC2] ( docs.aws.amazon.com/AmazonECS/latest/develo.. )

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

Did you find this article valuable?

Support MandrakeTech Blog by becoming a sponsor. Any amount is appreciated!