Node v21.6.2 (npm v10.2.4)

Create project

Let’s use the command line to create our project my-vite-vue-ssr.

npm create vite-extra@latest my-vite-vue-ssr -- --template ssr-vue
Project Name: my-vite-vue-ssr
Scaffolding project in /Users/harianto/Projects/my-vite-vue-ssr...

Done. Now run:

  cd my-vite-vue-ssr
  npm install
  npm run dev
Check the browser: http://localhost:5173/

Follow other commands then continue.

Save your current Node & NPM version (for NVM).

node -v > .nvmrc
Important way to know your working Node Version and use NVM to load the correct one with: nvm use.

Initiate git with git init. And save the Initial state.

git init
Initialized empty Git repository in ~/git/my-vite-vue-ssr/.git/
# Stage all files
git add .
# Commit and Message it
git commit -avm "INIT my-vite-vue-ssr Node `node -v`"

Docker things

Add .dockerignore

# Created by .ignore support plugin (hsz.mobi)
### Node template
# Logs
/logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# TypeScript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

# parcel-bundler cache (https://parceljs.org/)
.cache

# next.js build output
.next

# nuxt.js build output
# .nuxt

# Nuxt generate
dist

# vuepress build output
.vuepress/dist

# Serverless directories
.serverless

# IDE / Editor
.idea

# Service worker
sw.*

# Mac OSX
.DS_Store

# Vim swap files
*.swp

# VSCode Settings
.vscode

# APP IGNORES
package-lock.json
.git
.docker-mount
Of course you can change this for your needs

Create Docker Node Image

Before we create Dockerfile we need to edit the package.json. In scripts we add more handy command lines.

I’m using Docker Hub User as dockeruser and project name as my-vite-vue-ssr. Use your own preferences and change the code accordingly.

  "scripts": {
    "docker": "cross-env NODE_ENV=production npm run dev",
    "docker:build": "npm run build && docker build -t dockeruser/my-vite-vue-ssr .",
    "docker:run": "docker run --rm -p 3000:3000 dockeruser/my-vite-vue-ssr",
    "docker:push": "npm run docker:build && docker push dockeruser/my-vite-vue-ssr"
  },
Add these lines to your package.json file.
See we’re using port 3000 instead of 5173

And move all devDependencies lines to dependencies.

During Docker build the script will only check dependencies.

See below the result.

{
  "name": "my-vite-vue-ssr",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "node server",
    "build": "npm run build:client && npm run build:server",
    "build:client": "vite build --ssrManifest --outDir dist/client",
    "build:server": "vite build --ssr src/entry-server.js --outDir dist/server",
    "preview": "cross-env NODE_ENV=production node server",
    "docker": "cross-env NODE_ENV=production npm run dev",
    "docker:build": "npm run build && docker build -t dockeruser/my-vite-vue-ssr .",
    "docker:run": "docker run --rm -p 3000:3000 dockeruser/my-vite-vue-ssr",
    "docker:push": "npm run docker:build && docker push dockeruser/my-vite-vue-ssr"
  },
  "dependencies": {
    "compression": "^1.7.4",
    "express": "^4.18.2",
    "sirv": "^2.0.4",
    "vue": "^3.3.13",
    "@vitejs/plugin-vue": "^4.5.2",
    "cross-env": "^7.0.3",
    "vite": "^5.0.10"
  },
  "devDependencies": {}
}
File: package.json. Resulting lines

Create Dockerfile

Since my node version is v21.6.2. I’m looking which Alpine version from https://hub.docker.com/_/node/ and look for available version number -alpine.

node:21.6.2-alpine
FROM node:21.6.2-alpine

EXPOSE 3000

ENV NODE_ENV=production
ENV PORT=3000
ENV NODE_WORKDIR=/app
WORKDIR $NODE_WORKDIR

COPY package.json $NODE_WORKDIR/
RUN npm shrinkwrap
RUN npm i
COPY . $NODE_WORKDIR
RUN npm run build

CMD ["npm", "run", "docker"]
File: Dockerfile. In Docker environment the files are being copied to /app directory. And exposes port 3000

Build Docker Image

Create Docker Image: dockeruser/my-vite-vue-ssr.

Since we made special commands in package.json we can build from it, without knowing long strings of commands. Just peek it in.

npm run docker:build
Command Shortcut: npm run build && docker build -t dockeruser/my-vite-vue-ssr .

Hopefully everything goes well, and we can look up with in command: docker images.

REPOSITORY                         TAG                 IMAGE ID       CREATED              SIZE
dockeruser/my-vite-vue-ssr         latest              323b18f70290   About a minute ago   211MB

Test Docker Image

Let’s use the command and check the web: http://localhost:3000/

npm run docker:run

Kill Running Image

To kill the image, first we need to see what’s running again on port 3000. With this command below we can see what’s going on.

docker ps | grep 3000
7d32fd2396d8   dockeruser/my-vite-vue-ssr           "docker-entrypoint.s…"   13 minutes ago   Up 13 minutes   0.0.0.0:3000->3000/tcp                     stupefied_cohen
Remember the first column value: 7d32fd2396d8

Use this info 7d32fd2396d8 to kill the process.

docker rm -f 7d32fd2396d8
Killing Docker Process 7d32fd2396d8

Other useful docker commands

# see docker images
docker images

# remove IMAGE ID ex. baabdd69cf7a
docker rmi -f baabdd69cf7a

# see dangling images
docker images -q --filter "dangling=true"

# remove untagged images
docker rmi -f `docker images -q --filter "dangling=true"` > /dev/null 2>&1 || echo "Nothing to remove"

Conclusion

This is the way to build your own docker image. Every time you have new changes you can run again: npm run docker-build.

And if you have Docker Hub you can push it with: npm run docker:push.

Also don’t forget to commit your git.

Let me know what you think of this article?