A step-by-step guide to develop and deploy Vue apps with docker, part one

Vue is a great framework to develop user interfaces. It has experienced a great deal of growth in popularity since its initial release in 2014 and still continues to improve. In this article, you'll learn how to make your Vue development workflow even better using Docker

Previously, I've described a very simple way to develop and deploy a Vue.js app using a combination of git and npm. This works fine to quickly prototype an app and see how it behaves in the wild. In case you're in for a productive project, you probably want to use a more predictable end-to-end workflow.

This series of articles will equip you with the knowledge to create, develop and deploy a Vue project with Docker. With some tweaks, you can also use the featured Dockerfiles to deploy any project, using other frameworks such as React or Svelte.

Introducing Docker

Docker is a tool to build and deploy containerized units of software. So next to the source code for the application, a Docker project will also bring the environment to run it.

In a nutshell, compared to the quick & dirty approach I've described previously, there are several significant advantages, such as:

  • Node.js is not required on the hosting machine, neither on your local device, for development, testing, or productive usage.
  • The installation of node modules and the building of the app can be done inside the container(s).
  • We can easily replace the static express folder with a 'real' server. In this case, we'll use nginx to serve the web app.
  • Sharing code and replicating errors in a team context is much easier.
  • Docker itself comes with some goodies, such as networks and docker-compose, making it easy to manage apps, APIs, and databases altogether.

Docker is built around two core structures: Containers and Images.
To not confuse these two, keep the following in mind when reading ahead:

  1. Images are blueprints for containers. They include the source code and the required runtime, like Python or Node.js
  2. Containers are living units of software. They are running based on an underlying image.

If you would like to dig deeper into how Docker helps you with your development workflow, you can find some references at the end of this article.

Installing Docker

For the scope of this article, we want to make use of all of Docker's capabilities. That means: You need to have no other tool installed but Docker itself. We'll use it to execute all further setup steps for the Vue development and build process.

Linux (Ubuntu) quick setup

Taken from https://docs.docker.com/engine/install/ubuntu/

# Remove previous versions of docker
sudo apt-get remove docker docker-engine docker.io containerd runc

# Update package list & install necessary dependencies
sudo apt-get update
sudo apt-get install \
  apt-transport-https \
  ca-certificates \
  curl \
  gnupg \
  lsb-release

# Add Docker's GPG key to your local mashine
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

# Install Docker
echo \
  "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Windows setup

As Windows does not support containerization out of the box, you will need Docker Desktop to keep following along. You can download it using the link below.

Install Docker Desktop on Windows
How to install Docker Desktop for Windows

Setting up the project

It is common for web frameworks to require some steps in between project initialization and deployment. To make sure this process can be replicated, Docker makes use of Dockerfiles, single files that describe steps to build an Image.

Naturally, you can use a local Node.js setup for development and containerize the app when it's ready for shipping. In this case, however, I'd like to leave the whole setup to Docker. So before we jump into development, let's start by setting an image that creates our project's structure and enables us to extend it.

The initial project structure

Change into a directory of your choice and create the following folder structure:

/
| - /dockerfiles
|   | - Setup.Dockerfile  # 1
|   | - Dev.Dockerfile    # 2
|   | - Deploy.Dockerfile # 3

To give you an idea of what these three Dockerfiles will help us achieve:

  1. This image is responsible to scaffold a basic project structure, as well as installing further npm packages.
  2. We will use the second one to serve the project during development.
  3. Image three is responsible for building and shipping the app once we're ready to do so.

So much for the theory. Let's walk through these steps now, one by one.

Step 1: Initialize the app

While it is common to use Docker for app development and deployment, in this case, we will also use it to set up our initial project structure. Like so, we can reduce the amount of software to be installed on our local machine and keep the setup process lean & replicable.

We'll start by using the Vue CLI to set up our app's structure. Since it depends on Node.js, we'll start FROM node:14 and add some additional command layers on top.

Into the Setup.Dockerfile, add the following content:

FROM node:14

WORKDIR /vue-setup

RUN npm install -g @vue/cli

# The following commands ensure access to our files
# If we left them out, changing files on our local setup
# would fail due to insufficient permissions. 
RUN userdel -r node

ARG USER_ID

ARG GROUP_ID

RUN addgroup --gid $GROUP_ID user

RUN adduser --disabled-password --gecos '' --uid $USER_ID --gid $GROUP_ID user

# Set the active user and open the interactive terminal
USER user

ENTRYPOINT [ "bash" ]

We can then build our vue_helper image using the following command.

# Build an image named vue_helper using the Setup.Dockerfile
# The build args manage permissions when executing commands from inside the container
docker build \
  --build-arg USER_ID=$(id -u) \
  --build-arg GROUP_ID=$(id -g) \
  -t vue_helper - < ./dockerfiles/Setup.Dockerfile

Executing the next command will bind the container's working directory to our local machine, using a bind-mount.

Make sure the replace /path/to/project/ with your own project path.
docker run -v /path/to/project/:/vue-setup -it vue_helper

Next, a terminal from inside the container will open. Here, we can now install the Vue app itself and add more npm modules, if necessary.

user@b24a617a1dfa:/vue-setup$ vue create vue_app

You will then be prompted through the standard Vue CLI setup. In case you are unsure what to choose, just confirm all standard steps.

Given everything till this point went well, you will notice a new directory named vue_app appearing in your project folder. It origins from inside the container and means that everything went according to plan and our project is ready to be worked on.

Let's recapitulate what happened till this point:

  • We've used Docker to create a new image named vue_helper.
  • It uses a bind-mount and an interactive session terminal to help us scaffold our Vue project.
  • By using Vue create inside the container with a dedicated user, we have a basic project boilerplate available on our local device - without ever installing anything on it.

Stay tuned for the next part, where we will:

  • Explore how to serve the containerized app during development.
  • Build an application image and have it run on our local machine.
  • Deploy the image to Dockerhub and serve it on a Digital Ocean Droplet

References

Docker 101 - self-paced tutorial

#LearnDocker

Official Docker documentation

Orientation and setup
Get oriented on some basics of Docker and install Docker Desktop.