Haven't read the previous article yet?
- Check out the first part of the Vue-Docker series here.
- Or if you're TL: DR - take me to the code.
Update: Check out 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
:
FROM node:14-alpine
WORKDIR /vue_app
EXPOSE 8080
CMD [ "npm", "run", "serve" ]
In case you wonder about the absence thenpm install
command: We'll use thevue_helper
container image from the first article to manage npm packages.
We can build the development container by running:
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 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:
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:
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 directoryvue_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 instead of the Vue CLI, you must currently (30.10.2021) pass a--host
flag in yourpackage.json
file:
{
"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 🌟.
You can now change the application to your heart's desire.
In the repository for this article, 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, 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. 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:
# 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'.
- The build-stage will build the app using the Node.js image
- The production stage will use an Nginx 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 for more information.
Once you're ready to ship your app, run:
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:
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.
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