Nuxt3 with docker ( ㄧ )

Stephen Chen
11 min readDec 25, 2023
Generate form Midjourney

紀錄使用 docker 配上全新的 Nuxt3 專案,包含本地開發還有部署

此篇假設讀者知曉基本的 docker、docker-compose 和 Nuxt3

然後為了方便會使用 dc 這 alias 來替代 docker compose

有別於其他做法,這邊所有的指令都需要進到 container 裡面去完成,所以即便 local machine 沒有安裝 yarn 以及 node 都可以完成。

想直接使用的人可以看 Source code

首先先創六個檔案

開一個全新的資料夾,在此資料夾底下創以下六個檔案

.env 
.env.example
Dockerfile
docker-compose.yml
Readme.md
.dockerignore

.env 跟 .env.example 內容如下

這邊會區分 Docker 跟 Application 方便之後區分

### Application ##################################



### Docker ##################################

# Node 版本至少要 v18.0.0 or newer
# https://nuxt.com/docs/getting-started/installation
DOCKER_NODE_VERSION=18.16.1

Readme.md

## Installation

cp .env.example .env

## Other....

寫一下教學方便後續的人使用

.dockerignore

Exclude files and directories from the build context.

# .dockerignore
/.nuxt
/.output
/node_modules

.gitignore
README.md

Dockerfile

FROM node:${NODE_VERSION}-slim as base

MAINTAINER "example@gmail.com"

WORKDIR /app

# By default, just keep the container running
CMD ["tail", "-f", "/dev/null"]

上面要注意最下面那行

tail -f /dev/null

是因為如果沒有使用,docker container 便不會一直運行著

docker-compose.yml

version: '3.8'
services:
frontend:
container_name: frontend
restart: on-failure
build:
context: .
args:
# DOCKER_NODE_VERSION 會去讀取 .env 裡面
- NODE_VERSION=${DOCKER_NODE_VERSION}
volumes:
- .:/app

以下給 ChatGPT 回答

注意一下 volumes 這邊,這邊之後會解說

volumes:
- .:/app

前置作業建立好,接著先 build image

# In root directory

dc build frontend
dc build frontend
docker images

可以透過 docker images 看到我們已經創了一個 image 了

透過 image 來啟動 container

# up 啟動 container
# -d 參數是背景運行 Detached mode: Run containers in the background

# In root directory
dc up -d frontend

frontend 這要跟 docker composer 裡面的 services 一樣

然後再透過以下指令來看一下 container 的狀態

# In root directory
dc ps

進去 container 裡面

# In root directory
dc exec frontend bash

然後

cd /
dc exec frontend bash

出現上面畫面代表已經成功進去了

Init Nuxt3 專案

我們透過 npx 來創建一個全新的 Nuxt3 專案

# In / directory
npx nuxi@latest init app -f

注意 app 跟 -f 這兩個,還記得上面 docker-compose.yml 裡面的 volumes 嗎

# . 代表當前 local machine 運行 docker 的根目錄
# /app 代表 container 裡面的路徑,這也是為什麼 npx nuxi@latest init app 要特別在 app 底下

volumes:
- .:/app

如果不用 -f ( override file ) 則會出現資料夾存在的 error

當成功之後你會發現多了很多檔案

測試一下

在 container 裡面

cd app/ && yarn dev

點開瀏覽器會發現

其原因是因為 container 裡面沒有把 3000 port 給 expose 出來

所以來改一下 docker-compose.yml,加上 ports

services:
frontend:
container_name: frontend
restart: on-failure
build:
context: .
args:
# DOCKER_NODE_VERSION 會去讀取 .env 裡面
- NODE_VERSION=${DOCKER_NODE_VERSION}
ports:
# 把本機的 port 跟 container 的 port 綁定
- '${DOCKER_HOST_MACHINE_PORT}:3000'
volumes:
- .:/app

然後在 .env.example 還有 .env 也加上

### Application ##################################


### Docker ##################################

# Node 版本至少要 v18.0.0 or newer
# https://nuxt.com/docs/getting-started/installation
DOCKER_NODE_VERSION=18.16.1
DOCKER_HOST_MACHINE_PORT=3000

這樣就綁定本機的 3000 跟 docker container 的 3000 port

但因為我們有修改 docker-compose.yml 所以這邊要重新啟動

首先 control + c 把當前 yarn dev 給 exit 掉,然後在 exit 離開 container

接著一次 run 三個指令

  • dc down:停止當前所有正在運行ㄉㄜ container
  • dc up -d frontend:啟動 container
  • dc exec frontend bash:是進入 container
# In local machine root directory
dc down && dc up -d frontend && dc exec frontend bash

進入 container 裡面之後

yarn dev

這時候回到瀏覽器你會發現畫面已經正常顯示了

接著建立簡單的 pages

app.vue

<template>
<div>
<NuxtLoadingIndicator />
<NuxtPage />
</div>
</template>

新建一個 folder 叫 pages 底下有 index.vue 裡面簡單一個 count

<template>
<h1>{{ count }}</h1>
</template>

<script setup lang="ts">

let count = 0

</script>

我透過修改 count 然後看看畫面是否會有變動,如畫面變動恭喜成功

到這邊我們已經算是完成了全部,不透過 local machine 去創建專案,反而是進去 container 把 Nuxt3 專案創起來,然後在本機開發看看是否可以成功在瀏覽器顯示

當開發完畢要部署到 server

首先要 deploy 到 server 的話,我們要準備兩個檔案

1. build-prod.sh

創一個 bin 的 folder 裡面再創一個 build-prod.sh

#!/bin/bash

# 拿到當前路徑
CURRENT_DIRECTORY=$(dirname "$0")

echo "CURRENT_DIRECTORY: $CURRENT_DIRECTORY"

# 回到根路徑
cd "$CURRENT_DIRECTORY/../ || exit"

# 安裝 yarn
# --prefer-offline
#
# use network only if dependencies are not available in local cache
#
# --frozen-lockfile
#
# don't generate a lockfile and fail if an update is needed
#
# --non-interactive
#
# do not show interactive prompts
#
# --production=false
#
# install devDependencies
yarn install \
--prefer-offline \
--frozen-lockfile \
--non-interactive \
--production=false

# 執行 yarn build
yarn build

接著我們會需要另外一個檔案專門讓 docker-compose 處理 production 專用的

2. docker-compose.prod.yml

version: '3.8'
services:
frontend:
container_name: frontend
restart: on-failure
build:
context: .
args:
- NODE_VERSION=${DOCKER_NODE_VERSION}
ports:
# 把本機的 port 跟 container 的 port 綁定
- '${DOCKER_HOST_MACHINE_PORT}:3000'
volumes:
- .:/app
command: node .output/server/index.mjs
tty: true
stdin_open: true

command 跟 tty 還有 stdin_open 的解釋

接著一樣進到 container

dc exec frontend bash

執行 build-prod.sh

bash bin/build-prod.sh

執行完之後退出

接著執行 docker-compose

# In local machine

# 執行 docker-compose,而執行的時候讀取 docker-compose.prod.yml
# --build 是 build image
# -d 是 Detached mode: Run containers in the background
docker compose -f docker-compose.prod.yml up --build -d
docker compose -f docker-compose.prod.yml up — build -d

這樣就完成 prod 的版本了

結論

所以整理一下,不管我們要做什麼事情,都一定要先進到 conainter 去執行,執行完才回到 local machine,

Nuxt3 with docker Nginx deploy ( 二 )

Reference

--

--