Docker vue3 nginx docker-compose 打包

搞一个vue的HelloWord

涉及名词

nodejs

npm
pnpm
cnpm(社区)
yarn (Facebook )

vue
vuex
vue-cli
vue-router
vue-resource

pinia
webpack
eslint

vue init webpack my-project (项目名称都是小写字符)  -- Vue CLI 2.x
vue create my-project       -- Vue CLI 3.x 及以后

cnpm install 安装依赖
npm run dev   开发环境启动
npm run build  项目打包
访问:http://localhost:8080/#/


环境准备

cnpm安装
参考:https://blog.csdn.net/Sindyue/article/details/104051363
安装:npm install -g cnpm --registry=https://registry.npm.taobao.org
验证:cnpm -v

安装vue-cli
安装:npm install vue-cli -g
验证:vue list

初始化工程

# vue-cli 2 的创建方式,参考

D:\workspace3\docker-test1>vue init webpack frontend

# 删除文件夹

D:\workspace3\docker-test1>rmdir /s /q frontend

# 创建项目

D:\workspace3\docker-test1>pnpm create vue frontend

# 安装依赖:pnpm install

# 格式化:pnpm format

# 启动:pnpm dev

验证:http://localhost:5173/

# DevTools工具: http://localhost:5173/__devtools__/

pnpm dev 启动开发服务器(你现在正在运行)

pnpm build     打包构建生产版本

pnpm preview 预览打包后的生产版本

Vue DevTools

http://localhost:5173/

在任何一个Vue页面按:Alt+Shift+D启动Vue DevTools

frontend目录介绍

index.html:这是项目的入口 HTML 文件。Vite 会以它为中心,在开发时直接注入 JavaScript 模块,在生产构建时也会基于它来生成最终的静态文件。

package.json:项目的配置文件,列出了项目名称、版本、脚本命令(如 dev、build)以及所有生产与开发依赖。

pnpm-lock.yaml:由 pnpm 自动生成,它锁定了所有依赖包的精确版本,确保你和团队成员安装的依赖完全一致。

vite.config.ts:Vite 的配置文件,你可以在这里配置代理、插件、路径别名等。因为是 TypeScript 文件,编写时会有智能提示。

tsconfig.json:TypeScript 的配置文件,决定了如何编译项目中的 TypeScript 代码。

env.d.ts:TypeScript 环境声明文件,主要用于让 TypeScript 识别 .vue 文件以及其他环境变量(如 import.meta.env),避免报错。

.eslintrc.cjs、.prettierrc.json 等:代码检查和格式化工具的配置文件,用于统一团队代码风格。

src/

├── assets/          # 静态资源目录

│   └── main.css     # 项目的主样式文件(示例)

├── components/      # 公共组件目录

│   └── HelloWorld.vue # 一个示例组件

├── router/          # 路由配置目录

│   └── index.ts     # Vue Router 的配置,定义路径与组件的对应关系

├── views/           # 页面级组件目录

│   ├── AboutView.vue

│   └── HomeView.vue

├── App.vue          # 根组件,所有页面的最外层容器

└── main.ts          # 应用的入口文件,负责创建 Vue 应用并挂载到 DOM

各子目录说明:

  • assets/:存放项目中需要经过构建工具处理的静态资源,比如全局 CSS 文件、图片、字体等。
  • components/:存放可复用的 UI 组件,例如一个 Button.vue、Card.vue。它们通常被 views/ 里的页面组件调用。
  • router/:存放 Vue Router 的配置。index.ts 里定义了路由规则(如 / 对应 HomeView,/about 对应 AboutView)。
  • views/:存放页面级别的组件。这里的组件通常对应一个完整的“页面”,被路由直接加载。
  • App.vue:整个应用的根组件,在 main.ts 中被引入并挂载。你可以在它里面放置全局布局,比如导航栏、侧边栏。
  • main.ts:项目的 JavaScript 入口点。在这里会创建 Vue 应用实例,并注册路由、全局组件等。

后端接口

Docker本地用Dockfile 构建Java后端SprintBoot镜像-CSDN博客

http://localhost:18080/health
success ... ,count:11

App.vue

<template>
  <div class="container">
    <h1>后端健康检查</h1>

    <!-- 显示结果 -->
    <div class="result-box">
      <p v-if="responseData">{{ responseData }}</p>
      <p v-else class="placeholder">点击下方按钮获取数据</p>
    </div>

    <!-- 按钮 -->
    <button @click="fetchHealth" :disabled="loading">
      {{ loading ? '加载中...' : '获取健康状态' }}
    </button>

    <!-- 历史记录 -->
    <div v-if="history.length > 0" class="history">
      <h3>历史记录</h3>
      <ul>
        <li v-for="(item, index) in history" :key="index">
          {{ item }}
        </li>
      </ul>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

// 响应式数据
const responseData = ref<string>('')
const loading = ref(false)
const history = ref<string[]>([])

// 调用后端接口
const fetchHealth = async () => {
  loading.value = true

  try {
    const response = await fetch('/api/health')

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`)
    }

    const text = await response.text()
    responseData.value = text

    // 添加到历史记录
    history.value.push(text)
  } catch (error) {
    console.error('请求失败:', error)
    responseData.value = `❌ 请求失败: ${error}`
  } finally {
    loading.value = false
  }
}
</script>

<style scoped>
.container {
  max-width: 600px;
  margin: 50px auto;
  padding: 30px;
  font-family: Arial, sans-serif;
  background: #f5f7fa;
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

h1 {
  color: #42b883;
  text-align: center;
  margin-bottom: 30px;
}

.result-box {
  background: white;
  padding: 20px;
  border-radius: 8px;
  min-height: 60px;
  margin-bottom: 20px;
  border: 1px solid #e0e0e0;
  word-break: break-all;
}

.result-box p {
  margin: 0;
  font-size: 16px;
}

.placeholder {
  color: #aaa;
  text-align: center;
}

button {
  width: 100%;
  padding: 12px;
  font-size: 16px;
  background: #42b883;
  color: white;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.2s;
}

button:hover:not(:disabled) {
  background: #33a06f;
}

button:disabled {
  background: #a0d4b8;
  cursor: not-allowed;
}

.history {
  margin-top: 30px;
  padding-top: 20px;
  border-top: 1px solid #e0e0e0;
}

.history h3 {
  color: #333;
  margin-bottom: 10px;
}

.history ul {
  list-style: none;
  padding: 0;
}

.history li {
  background: white;
  padding: 8px 12px;
  margin-bottom: 6px;
  border-radius: 4px;
  border-left: 3px solid #42b883;
  font-size: 14px;
  word-break: break-all;
}
</style>

反向代理配置

vite 是vue 本地开发的方向代理,类似nginx。正式环境用nginx。

如果不配置代理,index.js中直接访问:http://localhost:8080/health,但有跨域问题。

const response = await fetch('/api/health')

const response = await fetch('http://localhost:8080/health')

vite.config.ts:

import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueDevTools from 'vite-plugin-vue-devtools'

export default defineConfig({
  plugins: [vue(), vueDevTools()],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url)),
    },
  },
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, ''),
      },
    },
  },
})

用本地nginx代理前后端

pnpm build

D:\workspace3\docker-test1\frontend>pnpm build

$ run-p type-check "build-only {@}" --

$ vue-tsc --build

$ vite build

vite v8.2.1 building client environment for production...

✓ 25 modules transformed.

computing gzip size...

dist/index.html                  0.43 kB │ gzip:  0.28 kB

dist/assets/index-Czm2Fkpr.css   1.18 kB │ gzip:  0.48 kB

dist/assets/index-VN4qfhsc.js   88.11 kB │ gzip: 34.51 kB

✓ built in 577ms

D:\workspace3\docker-test1\frontend>

# build后生成:

nginx config

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    access_log /var/log/nginx/access.log main;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;

    server {
        listen 80;
        server_name localhost;
        
        access_log /var/log/nginx/access.log main;
        error_log /var/log/nginx/error.log;
		
		root /usr/share/nginx/html;

        location ~* \.(js|mjs|jsx|ts|tsx)$ {
            types { 
                application/javascript js mjs; 
            }
            expires 1y;
            add_header Cache-Control "public, immutable";
            try_files $uri =404;
        }

        location ~* \.(css)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }

        location ~* \.(png|jpg|jpeg|gif|ico|svg|webp)$ {
            expires 1y;
            add_header Cache-Control "public, immutable";
        }


        location / {
            try_files $uri $uri/ /index.html;
        }

        location /api/ {
            proxy_pass http://172.17.0.2:8080/;  
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
			
			proxy_connect_timeout 60s;
            proxy_send_timeout 60s;
            proxy_read_timeout 60s;
			
        }
    }
}

docker nginx

docker run -d  --name nginx1  -p 8081:80  -v D:/workspace3/docker-test1/frontend/dist:/usr/share/nginx/html  -v D:/workspace3/docker-test1/nginx/config/nginx.conf:/etc/nginx/nginx.conf:ro  -v D:/workspace3/docker-test1/nginx/logs:/var/log/nginx  --restart=always --network app-network nginx

# 命令:

命令换行,window是^,linux是 \

docker run -d  --name nginx1  ^

-p 8081:80  ^

-v D:/workspace3/docker-test1/frontend/dist:/usr/share/nginx/html  ^

-v D:/workspace3/docker-test1/nginx/config/nginx.conf:/etc/nginx/nginx.conf:ro  ^

-v D:/workspace3/docker-test1/nginx/logs:/var/log/nginx  ^

--restart=always ^

--network app-network ^

nginx

# 命令参数

-v 挂载主配置文件,:ro 表示只读,防止容器内部误修改

--restart=always:设置容器在 Docker 重启后自动启动

# 前端静态文件

D:/workspace3/docker-test1/frontend/dist

# 本地nginx配置文件:

D:/workspace3/docker-test1/nginx/config/nginx.conf

# nginx日志文件

D:/workspace3/docker-test1/nginx/logs

# 重启容器

docker restart nginx1

docker network常用命令

# 1. 创建网络

docker network create app-network

# 2. 查看所有网络

docker network ls

# 3. 让已有容器加入网络

docker network connect app-network nginx1

docker network connect app-network dt1

或者启动容器添加:--network app-network 参数

# 4. 让容器离开网络

docker network disconnect app-network nginx1

# 5. 查看网络详细信息

docker network inspect app-network

# 6. 删除网络(需要先断开所有容器)

docker network rm app-network

# 7. 清理未使用的网络

docker network prune

修改nginx.conf配置文件

proxy_pass http://dt1:8080/

dt是后端的容器名称

docker network inspect

docker network inspect app-network

"IPv4Address": "172.18.0.3/16",

D:\workspace3\docker-test1\frontend>docker network inspect app-network
[
    {
        "Name": "app-network",
        "Id": "0ca1cfdaa6119901a4ff5ade1b1b858ce8eb7662d11286b6c98b962f44e7ae9c",
        "Created": "2026-08-19T06:25:47.859658629Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv4": true,
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Options": {
            "com.docker.network.enable_ipv4": "true",
            "com.docker.network.enable_ipv6": "false"
        },
        "Labels": {},
        "Containers": {
            "531d52cec028d6638b3c90aec93707100c3ea158a5df3c9fba06c055ec938aa0": {
                "Name": "nginx1",
                "EndpointID": "b4191134016226c38bfd78ab952b986951bd40c07a90a6e50b951562f0fde066",
                "MacAddress": "56:d0:2b:11:78:54",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            },
            "87cc51dba7ceff244392128bc598f47cb9a70676ba19154bd0056eda44fbe5ff": {
                "Name": "dt1",
                "EndpointID": "5442af5fbfe60382191347e6dc6c22c4fb152116a0032510d81fb8d6ec59a44e",
                "MacAddress": "66:6d:f4:05:5e:5d",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            }
        }
    }
]

查看后端dt1的ip

D:\workspace3\docker-test1\frontend>docker inspect dt1

docker-compose

AI生成docker-compose配置文件

docker run -d --name dt1 -p 8080:8080 --network app-network -v D:/workspace3/docker-test1/logs:/opt/logs docker-test:1.0

docker run -d  --name nginx1  -p 8081:80  -v D:/workspace3/docker-test1/frontend/dist:/usr/share/nginx/html  -v D:/workspace3/docker-test1/nginx/config/nginx.conf:/etc/nginx/nginx.conf:ro  -v D:/workspace3/docker-test1/nginx/logs:/var/log/nginx  --restart=always --network app-network nginx

再加一个nginx.conf配置文件。

依据上面的配置生成 docker-compose的配置文件

docker-compose 命令

# 启动所有服务

docker-compose up -d

# 停止所有服务

docker-compose down

# 查看日志

docker-compose logs -f

# 重启服务

docker-compose restart

启动:docker-compose up -d

启动一次启动相关容器,先后根据配置。

D:\workspace3\docker-test1>docker-compose up -d

暂停:docker-compose down

一次性暂停所有涉及容器。

D:\workspace3\docker-test1>docker-compose down

本地验证

http://localhost/

学习视频

非常好的docker视频,免费的。

黑屏视频地址

更多推荐