Angular Containerized Development using Docker with Dev Containers within Visual Studio Code

What

Angular containerized development environment with Docker and Visual Studio Code

When

Rapid development is becoming the de-facto standard for a dynamic development environment. Traditional build setups, that involves dependencies on the hosting environment poses a great challenges for developers.

Why

The following reasons explains the possible conditions that a containerized development setup for angular using docker and visual studio code is worth to consider.

  • Consistency, all development machines can use the same setup and configurations without worrying of hosting machines.
  • Easy pull the repository and all the development dependencies are available. Easy for neophyte developers to build a containerized development environment.
  • The host machines are non-polluted with dependency nightmares
  • The docker development machine is containerized, obvious benefits outweighs traditional development build setup.

How

Prerequisites

  • Visual Studio Code
  • Docker
  • ‘Remote Containers’ extension for Visual Studio Code

Getting started

Setup Visual Studio Code and Remote Containers

Create a folder, use your drive preference

PS> mkdir D:\Docker\Angular\BasicUnderConstruction

PS> cd D:\Docker\Angular\BasicUnderConstruction

Use visual studio code, I’m using code-insiders version

PS> code-insiders . or

PS> code .

Development Container

In visual studio code, press F1 function key. Search and add for Add Development Container Configuration Files. Note: Remote Container plugin must be installed, as per prerequisite.

Now Search for Node.js & TypeScript

Select node version 16

There’s no need for any additional features, select OK

Visual studio popup action will appear, Reopen in Container

Note: If the popup doesn’t show up, hit F1 and search for Remote Containers: Rebuild Container

Reopen in Container can take a while for the first time, subsequent reopens can make load times faster. Once done, the bottom-left corner of Visual Studio Code should look like:

No obvious difference is noticeable visually other than the Explorer will have .devcontainer and the title will have (DEV CONTAINER: NODE.JS)

To verify that our remote container is working, open a Terminal, you will have a node prompt that is either Windows or WSL

The docker container remote environment is ready but Angular is not installed nor prepared to handle project development.

Install Angular

Open up the Dockerfile in the .devcontainer folder

Uncomment the line to install global node packages, and add the angular cli.

You can check the latest version at: https://www.npmjs.com/package/@angular/cli?activeTab=versions

# [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18, 16, 14, 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster
ARG VARIANT=16-bullseye
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT}

# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
#     && apt-get -y install --no-install-recommends <your-package-list-here>

# [Optional] Uncomment if you want to install an additional version of node using nvm
# ARG EXTRA_NODE_VERSION=10
# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}"

# [Optional] Uncomment if you want to install more global node modules
RUN su node -c "npm install -g @angular/[email protected]"
RUN su node -c "npm install -g node-sass"
RUN su node -c "npm install -g sass-loader"
RUN su node -c "npm install -g raw-loader"

Without the version, you will get the latest. For consistency, version can be specified, as seen from the Dockerfile above.

Press F1, Remote Containers: Rebuild Container (Rebuild and Reopen Container, if fully disengaged from remote) to affect changes to the remote container environment.

On the terminal, check if angular is working, issue a ng version command. On successful cli installation, the following will be displayed.

Create an Angular application

On the terminal:

  • ng new under-construction (Select defaults, press Enter. Packages and scaffolding will be created by npm and angular)
  • cd under-construction
  • ng build
  • ng serve #OR ng serve --poll=2000 (application should now be running in http://localhost:4200, open in your preferred browser. The poll helps in reloading, if changes occurs in files)
Extensions

Development container’s major advantage against traditional setup is the capability to configure Visual Studio Code IDE with specific extensions for the project.

Add the following extensions to the devcontainer.json

// Configure tool-specific properties.
"customizations": {
	// Configure properties specific to VS Code.
	"vscode": {
		// Add the IDs of extensions you want installed when the container is created.
		"extensions": [
			"dbaeumer.vscode-eslint",
			"lucono.karma-test-explorer",
			"angular.ng-template",
			"johnpapa.angular2",
			"alexiv.vscode-angular2-files",
			"esbenp.prettier-vscode",
			"dbaeumer.vscode-eslint",
			"shardulm94.trailing-spaces"
		]
	}
},

Press F1, Remote Containers: Rebuild Container to affect changes to the remote container environment.

Feel free to add additional extensions, as the project needs arises. Above are the common extensions to get you started.

Testing

Before this can be classed as a ‘dev environment’, we need to be able to run unit tests.

On the terminal, if the application is running, issue Ctrl + C. Then run the angular test

  • ng test (on the project application directory, [under-construction directory from the example above], not the root folder)

Docker does not have a browser installed. The browser helps in running the build so that it can be tested. The Dockerfile must be updated.

# [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 18, 16, 14, 18-bullseye, 16-bullseye, 14-bullseye, 18-buster, 16-buster, 14-buster
ARG VARIANT=16-bullseye
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT}

# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
#     && apt-get -y install --no-install-recommends <your-package-list-here>

# [Optional] Uncomment if you want to install an additional version of node using nvm
# ARG EXTRA_NODE_VERSION=10
# RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}"

# [Optional] Uncomment if you want to install more global node modules
RUN su node -c "npm install -g @angular/[email protected]"
RUN su node -c "npm install -g node-sass"
RUN su node -c "npm install -g sass-loader"
RUN su node -c "npm install -g raw-loader"

RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -

RUN sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'

RUN apt-get update && apt-get install -y google-chrome-stable

Karma needs to run Chrome in headless mode or we will get errors. Go into the Karma config file (karma.conf.js), and replace browsers:['Chrome'] with

// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html

module.exports = function (config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine', '@angular-devkit/build-angular'],
    plugins: [
      require('karma-jasmine'),
      require('karma-chrome-launcher'),
      require('karma-jasmine-html-reporter'),
      require('karma-coverage'),
      require('@angular-devkit/build-angular/plugins/karma')
    ],
    client: {
      jasmine: {
        // you can add configuration options for Jasmine here
        // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
        // for example, you can disable the random execution with `random: false`
        // or set a specific seed with `seed: 4321`
      },
      clearContext: false // leave Jasmine Spec Runner output visible in browser
    },
    jasmineHtmlReporter: {
      suppressAll: true // removes the duplicated traces
    },
    coverageReporter: {
      dir: require('path').join(__dirname, './coverage/under-construction'),
      subdir: '.',
      reporters: [
        { type: 'html' },
        { type: 'text-summary' }
      ]
    },
    reporters: ['progress', 'kjhtml'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    browsers: ['ChromeHeadlessNoSandbox'],
    customLaunchers: {
      ChromeHeadlessNoSandbox: {
        base: "ChromeHeadless",
        flags: [
          "--no-sandbox",
          "--disable-setuid-sandbox"
        ]
      }
    },
    singleRun: false,
    restartOnFileChange: true
  });
};

Fully reload the folder again in Visual Studio Code by closing folder and closing remote connection.

Press F1, Remote Containers: Rebuild Container (Rebuild and Reopen Container, if fully disengaged from remote) to affect changes to the remote container environment. Rerun the following in the terminal.

  • cd under-construction (go to the under-construction application directory)
  • ng test (accept defaults)
Test Explorer

Karma provides a test explorer on the left side navigation pane. This provides a more environment feel than the terminal. Configure karma by:

  • On the explorer, go to the root directory (root directory not the project directory, in this example BasicUnderConstruction)
  • right click, make a directory, .vscode
  • inside .vscode, right click and make settings.json file and paste the following:
{
  "karmaTestExplorer.projectRootPath": "under-construction",
}

Press F1, Remote Containers: Rebuild Container (Karma reloads, force reload, if needed)

Run the test with he play button on the left side testing pane

References

Angular Development in Docker with Dev Containers (https://itnext.io/angular-development-in-docker-with-dev-containers-49d2cabad445)