前端项目 Docker 打包实操指南

🐳 前端项目 Docker 打包实操指南

------ 从零到跑通,在你的电脑上一步一步把 Vue 项目打包成 Docker 镜像

📋 本文目录

  1. 准备工作(确认环境)
  2. 第一步:本地构建前端
  3. 第二步:创建 Docker 三件套
  4. 第三步:构建 Docker 镜像
  5. 第四步:运行容器并验证
  6. 日常开发常用命令
  7. 常见问题 FAQ

1. 准备工作:确认环境就绪

1.1 Docker Desktop 正在运行?

看右下角任务栏有没有 Docker 鲸鱼图标。打开 PowerShell 运行:

shell 复制代码
docker version --format "{{.Server.Version}}"

如果能输出版本号(如 24.0.7),说明 Docker daemon 正常。如果报错,先启动 Docker Desktop 等它变成绿色。

1.2 Node.js 和依赖

shell 复制代码
node -v    # 需要 Node 16+
npm -v     # 任意版本
# 项目根目录下要有 node_modules/ 目录
Test-Path node_modules   # PowerShell,返回 True 才对

1.3 确认项目结构

你的项目根目录应该长这样:

text 复制代码
webName/
├── src/                    ← 前端源码
├── package.json            ← 依赖和构建脚本
├── vite.config.js          ← Vite 配置
├── docker/
│   ├── Dockerfile          ← 要创建的
│   ├── nginx.conf           ← 要创建的
│   └── static_file/         ← 已存在,头像图标等
└── dist/                    ← 构建产物(下一步生成)
    ├── index.html
    ├── static/
    └── ...

2. 第一步:本地构建前端

在项目根目录打开 PowerShell,运行:

shell 复制代码
cd D:\pro\webName
$env:NODE_OPTIONS="--max-old-space-size=8192"   # Node 默认 2GB 不够,加内存
npm run build:prod

⚠️ 为什么要加 NODE_OPTIONS?

你的项目有 4500+ 模块,默认 Node 堆内存 2GB 不够用,会报 JavaScript heap out of memory。设置 --max-old-space-size=8192 给 8GB 就够了。这个设置只在当前 PowerShell 窗口生效,关掉窗口要重新设置。

构建成功后,dist/ 目录里会有 index.html、static/、font/ 等文件,大小约 30MB。

遇到构建错误?

如果报 Vue 模板语法错误(Invalid end tag)或导入路径错误,说明代码里有 bug,先修掉再继续。这次构建就是帮你发现这些问题的好机会。


3. 第二步:创建 Docker 三件套

在 docker/ 目录下创建 3 个文件。

3.1 Dockerfile

在 docker/Dockerfile 写入:

dockerfile 复制代码
# 基础镜像:nginx:alpine(~5MB,超小)
FROM nginx:alpine

# 设置时区
ENV TZ=Asia/Shanghai

# 复制 Nginx 配置文件
COPY docker/nginx.conf /etc/nginx/conf.d/default.conf

# 复制构建产物到 Nginx 静态文件目录
COPY dist /usr/share/nginx/html

# 复制静态资源文件(头像、图标等)
COPY docker/static_file /usr/share/static_file
RUN chown -R nginx:nginx /usr/share/static_file

# 声明监听端口
EXPOSE 80

# 启动 Nginx(daemon off = 前台运行,Docker 要求)
CMD ["nginx", "-g", "daemon off;"]

3.2 nginx.conf

在 docker/nginx.conf 写入:

nginx 复制代码
server {
    listen 80;
    server_name localhost;
    root /usr/share/nginx/html;
    index index.html;

    # ============ SPA 路由 fallback(重要!)============
    # Vue Router history 模式下,刷新子路由会 404
    # 先找 $uri 文件 → 再找 $uri/ 目录 → 都没有就返回 index.html
    location / {
        try_files $uri $uri/ /index.html;
    }

    # ============ API 反向代理 ============
    # 等后端部署好再打开,把 8080 改成后端端口
    # location /prod-api/ {
    #     proxy_pass http://host.docker.internal:8080/;
    #     proxy_set_header Host $host;
    # }

    # ============ 静态资源缓存 ============
    location ~* \.(js|css|png|jpg|svg|woff2?)$ {
        expires 7d;
        add_header Cache-Control "public, immutable";
    }

    # ============ 禁止访问隐藏文件 ============
    location ~ /\. { deny all; }
}

3.3 .dockerignore(项目根目录)

在项目根目录创建 .dockerignore,告诉 Docker 构建时忽略哪些文件:

text 复制代码
node_modules
*.log
.git
.github
.vscode
.idea
.env.local
npm-debug.log*
docker/docs
docker/*.tar.gz
*.md
.trae
.kilo
.mimocode

💡 为什么要用单阶段而不是多阶段构建?

多阶段构建(在 Docker 容器内跑 npm install + vite build)理论上更"专业",但你的项目有 4500+ 模块,Hyper-V VM 内存不够会崩。所以先用"主机 build + Docker 只打包运行时"的方式,稳定、快、好调试。等服务器上部署时再考虑多阶段。


4. 第三步:构建 Docker 镜像

在项目根目录运行:

shell 复制代码
docker build -t webName:v1.0 -f docker/Dockerfile .

参数拆解:

参数 含义
-t webName:v1.0 给镜像打标签,格式是 名字:版本
-f docker/Dockerfile 指定 Dockerfile 路径(不写的话默认找当前目录的 Dockerfile)
最后的 . 构建上下文目录,Docker 会把这个目录下所有文件发给构建引擎

成功后会看到:

text 复制代码
#10 naming to docker.io/library/webName:v1.0 done
#10 DONE 0.3s

验证镜像:

shell 复制代码
docker images webName
# REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
# webName      v1.0      0c670d47a203   22 seconds ago   99.4MB

✅ 镜像 99.4MB 正常

nginx:alpine 基础 ~5MB + dist ~30MB + static_file ~几十MB,加起来 99MB 没问题。如果是多阶段构建最终镜像会更小(~35MB),但当前方式够用。


5. 第四步:运行容器并验证

shell 复制代码
# 启动容器,映射端口 8080 → 80
docker run -d --name tds-web -p 8080:80 webName:v1.0
#           ^^  ^^^^^^^^^^  ^^^^^^^^^^  ^^^^^^^^^^^^^
#           |   |            |          镜像名:版本号
#           |   |            主机8080 → 容器80
#           |   容器名
#           后台运行

# 验证容器在跑
docker ps --filter "name=tds-web"

# 浏览器访问
# http://localhost:8080

浏览器打开 http://localhost:8080,应该能看到登录页面。🎉

🎯 如果页面空白或 404

检查 Nginx 配置里的 try_files $uri $uri/ /index.html; 是否正确。没有这行,Vue Router 的 history 模式刷新子路由会 404。

快速验证清单:

验证项 命令 / 操作 期望结果
容器在跑 docker ps STATUS 列显示 Up
HTTP 可访问 浏览器打开 localhost:8080 看到登录页面
刷新子路由 点一个菜单再 F5 不 404
进容器内部 docker exec -it tds-web sh 能 ls /usr/share/nginx/html

🎊 恭喜!你已经跑通了

刚才的完整流程回顾:

shell 复制代码
# 1. 本地构建前端
npm run build:prod

# 2. 创建 Dockerfile + nginx.conf + .dockerignore(已做好)

# 3. 构建 Docker 镜像
docker build -t webName:v1.0 -f docker/Dockerfile .

# 4. 运行容器
docker run -d --name tds-web -p 8080:80 webName:v1.0

# 5. 浏览器访问 http://localhost:8080 ✅

6. 日常开发常用命令

代码改了,重新部署:

shell 复制代码
# 停止并删除旧容器
docker rm -f tds-web

# 重新构建前端
npm run build:prod

# 重新构建镜像(tag 改版本号,或用 latest)
docker build -t webName:v1.1 -f docker/Dockerfile .

# 启动新容器
docker run -d --name tds-web -p 8080:80 webName:v1.1

查看日志:

shell 复制代码
# 查看容器日志
docker logs tds-web

# 实时追踪最后 100 行(Ctrl+C 退出)
docker logs -f --tail 100 tds-web

进容器调试:

shell 复制代码
docker exec -it tds-web sh
# 进去后可以:
ls /usr/share/nginx/html          # 看文件在不在
cat /etc/nginx/conf.d/default.conf  # 看 Nginx 配置
nginx -t                           # 测试 Nginx 配置语法

清理:

shell 复制代码
# 停容器
docker stop tds-web

# 删容器
docker rm tds-web

# 删镜像
docker rmi webName:v1.0

# 一键清理所有没用的镜像和容器(谨慎!)
docker system prune -a

7. 常见问题 FAQ

Q1: docker build 报 COPY dist not found

A: dist 目录被 .dockerignore 排除了。检查 .dockerignore 里有没有写 dist,有的话删掉(单阶段构建需要它)。

Q2: docker build 报 pull access denied 或超时

A: Docker Hub 在国内很慢。在 Docker Desktop → Settings → Docker Engine 里加镜像加速器:

json 复制代码
{
  "registry-mirrors": [
    "https://docker.1ms.run",
    "https://docker.xuanyuan.me"
  ]
}

点 Apply & Restart。

Q3: npm run build:prod 报 heap out of memory

A: Node 默认 2GB 不够。PowerShell 先设:$env:NODE_OPTIONS="--max-old-space-size=8192",再跑构建。

Q4: 页面能打开但 API 请求跨域

A: 这是前端和后端不在同一个 origin。两种解法:

  1. 推荐:Nginx 反向代理。在 nginx.conf 里取消 API 代理注释,把后端地址改成你实际的后端服务。
  2. 临时:后端开 CORS(不推荐长期用)。

Q5: Docker Desktop 启动报 WSL 错误

A: 你的系统用的是 Hyper-V 后端(settings.json 里 wslEngineEnabled: false)。不要改回 WSL,保持 Hyper-V 就行。

Q6: 端口被占用

shell 复制代码
# 查找谁占了 8080
Get-NetTCPConnection -LocalPort 8080 -ErrorAction SilentlyContinue | 
  Select-Object LocalPort, OwningProcess, @{N='Process';E={(Get-Process -Id $_.OwningProcess).Name}}

# 换个端口
docker run -d --name tds-web -p 9090:80 webName:v1.0
相关推荐
前端双越老师8 小时前
程序员 1v1 访谈系列第十二期:普通人没有核心竞争力
前端·ai编程·全栈
柳杉8 小时前
没有写一行代码:我用 Codex 制作 了一个 3D 智慧展厅可视化大屏
前端·ai编程·three.js
IT_陈寒8 小时前
Redis开发实战:从入门到精通
前端·人工智能·后端
恋猫de小郭8 小时前
Flutter Impeller Vulkan 内存持续上涨,问题没想到是文字阴影
android·前端·flutter
0xBADCODE9 小时前
2026 强网杯 Web 题 cwp · 全链路复盘
前端·安全·web安全·网络安全·系统安全·ctf
java_logo17 小时前
Docker 部署 Liquibase:轻松搭建数据库变更管理
数据库·docker·容器·数据库管理·liquibase·轩辕镜像·数据库变更
麦麦麦当劳大王17 小时前
【油猴脚本】Boss直聘 岗位职责复制
开发语言·前端·javascript
小lu飞18 小时前
2026小红书小工具怎么制作:纯前端 ZIP 打包、沙箱限制与笔记挂载流程
前端·笔记·ai·ai编程
smallcelebration19 小时前
151 从0开始搭建后端项目
前端·firefox
wangruofeng19 小时前
手机和电脑传文件,除了微信还有 LocalSend
前端