A step-by-step guide to developing and deploying Vue apps with docker, part two
Tags: devops, vue, docker, javascript
Published: 2021-11-15 06:55:40

> Haven't read the previous article yet?  
> \- Check out the [first part of the Vue-Docker series here](https://blog.q-bit.me/how-to-develop-and-deploy-a-vue-js-app-with-docker-part-one/).  
> \- Or if you're [TL: DR - take me to the code](https://github.com/tq-bit/vue-docker-development).

> Update: Check out [Chattergram](https://github.com/tq-bit/chattergram) for a full-stack approach to Vue 3 development with docker-compose

Build the dev - container
-------------------------

Now that we have Docker installed and scaffolded our project, we can start developing. Let's begin by adding the following to the `Dev.Dockerfile`:

```Dockerfile
FROM node:14-alpine

WORKDIR /vue_app

EXPOSE 8080

CMD [ "npm", "run", "serve" ]
```

> In case you wonder about the absence the  `npm install` command: We'll use the `vue_helper` container image [from the first article](https://blog.q-bit.me/how-to-develop-and-deploy-a-vue-js-app-with-docker-part-one/#setting-up-the-project) to manage npm packages.

We can build the development container by running:

```bash
docker build  \
    -f ./dockerfiles/Dev.Dockerfile \
    -t vue_app:dev 
    vue_app
```

You should then receive a container named `vue_app`. With it, we can start development.

**Note:** Given you have read the previous article, you'll notice a slight difference in the build commands. Previously, we've used [the STDIN method](https://docs.docker.com/engine/reference/commandline/build/#build-with--) to read the content of the dockerfile. While it's generally a bit faster, it specifies no **build context** to the Docker daemon. If you try and replicate the STDIN way to build the development app's container, you will run into an error:

```bash
COPY failed: forbidden path outside the build context: ../vue_app/package.json
```

The difference, in a nutshell, is that:

*   the STDIN method uses the context of the Dockerfile ( Path: ./dockerfiles/ )
*   while the `-f` - method uses the context of the currently active directory ( Path: ./ )

Develop with Docker
-------------------

To develop, we must keep the container's content synchronized with our local source code. This can easily be achieved by using a bind mount.

Let's launch the development container by executing the following command:

```bash
docker run \
    -v /path/to/project/vue_app:/vue_app \
    -p 8080:8080
    -it vue_app:dev
```

It will:

*   run a container based on the tagged image `vue_app:dev` and expose it on port 8080
*   sync the local working directory `/path/to/project/vue_app` with the container's working directory `vue_app` over a bind mount
*   Open an interactive session so you can keep track of your development server

> If you are trying to get the container up with [Vite](https://vitejs.dev/) instead of the Vue CLI,  you must currently (30.10.2021) pass a `--host` flag in your `package.json` file:

```js
{ 
  "scripts": { 
    // ... other scripts  
    "serve": "vite --host 0.0.0.0" 
  }
}
```

When the container is running, the app can be accessed over a browser. Open a new tab at `http://localhost:8080` and you will see the familiar Vue boilerplate. And thanks to the bind mount, modifications to the code on your local machine will be replicated straight into the container. Vue CLI will pick these up and reload the browser page.

Finally, try and change the `msg` property of the `HelloWorld` component. If the change is visible inside your browser - congratulations - you've successfully set up your own Docker dev-environment 🌟.

![](https://blog.q-bit.me/content/images/2021/10/image-2.png)

You can now change the application to your heart's desire.

> In the [repository for this article](https://github.com/tq-bit/vue-docker-development), I've created a simple to-do-list application that we can deploy later.

Prepare the app for deployment
------------------------------

We can already create & manage an app, as well as develop its source code using Docker. What's left to do is to make it ready for a productive environment - without the dev-server overhead.

There are several ways to do so. You could use the example from the [Quick & Dirty article I wrote earlier](https://blog.q-bit.me/quick-dirty-how-to-deploy-a-fullstack-vue-js-app-with-a-working-node-js-backend/), that is, a custom Express.js server. But why reinvent the wheel if there's a container to the rescue?

> The example you find below is inspired by [the official Vue 2 Docs](https://vuejs.org/v2/cookbook/dockerize-vuejs-app.html). It works equally well with any other kind of JS framework that use Webpack or Vite.

Let's fill the remaining `Deploy.Dockerfile` with life by adding these commands:

```dockerfile
# build stage
FROM node:14-alpine AS build-stage

WORKDIR /vue_app

COPY package.json ./

RUN npm install

COPY . .

RUN npm run build

# production stage
FROM nginx AS production-stage

COPY --from=build-stage /vue_app/dist /usr/share/nginx/html

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]
```

Docker can interpret these to declare two distinct stages. This procedure is commonly referred to as '[Multi-Stage Building](https://docs.docker.com/develop/develop-images/multistage-build/#name-your-build-stages)'.

*   The build-stage will build the app using the Node.js image
*   The production stage will use an [Nginx](https://nginx.org/en/) web server image.
*   It launches a container that serves the built Vue SPA on port 80

Stages refer to one another by using the `--from` - flag. Like this, you can streamline your development workflow. You could, for instance, extend the above commands by adding one or several test phases.

> At this point, you can also configure Nginx as per your project's requirements. Check out the [official docs on Dockerhub](https://hub.docker.com/_/nginx/) for more information.

Once you're ready to ship your app, run:

```bash
docker build \
    -f ./dockerfiles/Deploy.Dockerfile \
    -t vue_app:production \
    vue_app
```

You will receive an image that includes an optimized version of your app. It can be launched anywhere Docker is installed:

```shell
docker run -p 80:80 vue_app:production
```

The application will then be available under `http://localhost`.

Let's recap:

*   We've filled the two Dockerfiles for development and deployment with commands
*   Both provide us a unique way to develop and distribute our app
*   Docker also allows us to streamline our deployment process
*   This procedure is called 'Multi-Stage Building'

Example Github Repos
--------------------

I've collected all the code from the first two articles together in a Github Repos. You are welcome to use it either as a boilerplate or Proof of Concept.

https://github.com/tq-bit/vue-docker-development

Next steps
----------

While you could use the example as-is, there's still room for improvement. So in the next and final article of the series:

*   We'll use Dockerhub to publish our app image
*   We'll create a Virtual Host on Digital Ocean and deploy our app to it
*   Instead of running each docker command separately, we'll explore the usage of `docker-compose` for development and deployment