Dockerizing Angular Development Environment

Mar 30, 2019/4 min read
How and why you should keep your Angular development environment dockerized
angular
Dockerizing Angular Development Environment thumbnail

Prerequisites

I assume you already know Angular and Docker are. If not, I would recommend reading about Angular and Docker first.

Motivation

Creating or cloning an Angular development environment can get quite messy. After you installed your favorite IDE you will need to get npm, install some global and local packages and sometimes configure environment variables. Luckily this process can be automated with our lovely friend Docker!


Creating an Angular Project

Without further ado let's quickly clone the files we need from this repository and remove the README.md and LICENCE files. Now we can create our Angular project as we already know with the angular-cli by running :

docker-compose -f docker-compose.seed.yml run seed

With this, we tell docker-compose to use the file docker-compose.seed.yml and run a service named seed, the service will prompt you with project creation.

Note: For git-bash users, prefix interactive commands with winpty


Running Angular Development Server

Before running our development server, let's break down the Dockerfile and docker-compose.yml files

This is pretty straight forward, so let's recap this quickly

  • Set the base image to be the latest node:alpine for minimum image size
  • Install @angular/cli globally, any other global tools goes into this layer
  • Copy and install localy npm packages
  • Copy the remaining source code, this is the layer that changes the most.
  • It's important to note that there is a .dockerignore file that prevents certain file and file formats from being copied.

Port Mapping

Angular's development server default port is 4200, so we map the host'’'s port to the container'’'s one.

Volumes

As a thumb rule, we should try avoiding large volumes, this is the reason we don'’'t map the entire directory or node_modules directory. You probably noticed the :cached at the end of the first volumes, with this we tell docker whether the host or the container is authoritative. In general, we have two options, :cached the host to be authoritative, or :delegated where we want the container to be authoritative. Put simply, authoritative means which view has higher preference of being updated. These are the minimum files that I decided to volume, feel free to add other files and volumes.

Entrypoint

This is where we override the image'’'s ENTRYPOINT if it had one. We use the regular ng serve with 2 flags:

  • --host 0.0.0.0 which tells angular-cli to not use localhost, we need to specify this in order to access the development server from our browser.
  • --poll 1 tells angular-cli to poll changes every 1 millisecond
    Read more about docker-compose.yml

Running

We fire up the development server by running docker-compose up -d --build The flags set docker-compose to run in detached mode and recreate our image if it'’'s already built. Now we can inspect the logs with docker-compose logs -f dev After the server successfully started run docker-machine ip, browse to the returned ip at port 4200, trigger some changes and voila, the page reloads! Now you can attach to the container with docker-compose exec dev sh and run some angular-cli commands

Where is node_modules?

You might have noticed the IDE yelling at you for not having the node_modules directory, let'’'s quickly fix this by running:

docker cp dev:/usr/src/app/package-lock.json . && \
docker cp dev:/usr/src/app/node_modules - > node_modules.tar && \
 tar -xf node_modules.tar && \
 rm -f temp_node_modules.tar

With this batch of command we copying 2 things from the container to the host machine:

  1. packge-lock.json which is created at image build-time when the localy npm install happens
  2. node_modules directory, but to avoid symlink errors we first save them to a .tar file and then extracting at the host machine.

You will need to run these commands every time you npm install something, persist them with a script to run quickly.