Docker 前端本地开发指南(实操版)

Docker 前端本地开发指南(实操版)

本文只讲一件事:怎么用 Docker 把前端开发环境跑起来,并且能正常热更新。

如果你是想系统学习 Docker(生产部署、镜像仓库、K8s 等),请看完整版《Docker 开发与部署指南》;本文是它的"本地开发子集"------把日常开发真正用得上的部分提炼出来,砍掉所有延伸内容,照着做就行。


目录


一、为什么要用 Docker 跑前端开发

痛点 Docker 解决方案
团队成员 Node 版本不一致 镜像锁定版本,人人一样
Windows 装某些 npm 包失败(如 node-sass) 容器内是 Linux,原生兼容
新人入职装环境要半天 docker compose up 一条命令搞定
切换项目时依赖冲突 每个项目独立容器,互不干扰

一句话:把 Node 版本、依赖、启动命令全部固化进镜像,任何人、任何机器,一条命令拉出完全一致的开发环境。


二、核心概念速览(够用就行)

本地开发只需要理解三个词:

概念 通俗理解 本地开发里对应什么
镜像(Image) 应用的"安装包",只读模板 node:20-alpine + 你的项目依赖
容器(Container) 镜像跑起来的"活实例" 正在跑的 vite dev server
数据卷(Volume) Docker 管理的持久化存储 node_modules、数据库数据

三者关系:

markdown 复制代码
Dockerfile ──build──> Image(安装包)
                          │
                          │ docker compose up
                          ▼
                     Container(活实例)
                          │
                          │ 挂载
                          ▼
                     Volume(持久化数据)

本地开发只需要记住:容器 = 你项目的"独立运行环境",删了可以随时重建,不影响你的源码和依赖。


三、环境准备

3.1 安装 Docker Desktop

Windows 上装 Docker Desktop,安装后启动即可(默认用 WSL2 后端)。

3.2 配国内镜像加速(强烈建议)

国内直接访问 Docker Hub 经常超时,先配加速器:

Docker Desktop → Settings → Docker Engine:

json 复制代码
{
  "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://dockerproxy.com",
    "https://docker.mirrors.ustc.edu.cn",
    "https://hub-mirror.c.163.com"
  ]
}

Apply & Restart 生效。

3.3 确认后端地址

前端开发时请求要转发到后端(yudao-server)。两种常见情况:

后端在哪 前端配置
宿主机 IDE 里跑 http://host.docker.internal:48080
局域网某台机器跑 直接写 IP,如 http://192.168.1.182:48080

这个地址通过 compose 的 environment 注入(见下文 4.2),不用改代码。


四、三个核心文件

每个前端项目目录下都要有这三个文件。以 yudao-ui-admin-uniapp 为例(vue3 项目的差异见第十一章)。

4.1 Dockerfile.dev

dockerfile 复制代码
FROM node:20-alpine

# git 被 husky 间接需要;corepack 启用 pnpm@10
RUN apk add --no-cache git && corepack enable

WORKDIR /app

# 只拷依赖描述文件,利用 docker 层缓存(改代码不会触发重装依赖)
COPY package.json pnpm-lock.yaml .npmrc ./
# --ignore-scripts: 跳过 prepare 钩子(scripts/ 目录此时还没拷进来)
RUN pnpm install --frozen-lockfile --ignore-scripts

# 源码打进镜像(配合 compose watch 的 sync 实现热更新,见 4.2)
COPY . .

EXPOSE 9000

# 默认 H5 开发模式
CMD ["pnpm", "dev:h5"]

两个关键点

  • pnpm install 只拷了依赖描述文件 → 依赖装进镜像层,改代码不会重装;
  • COPY . . 把源码拷进镜像 → 不能删,热更新方案靠它(见第七章)。

4.2 docker-compose.dev.yml

yaml 复制代码
services:
  uniapp-dev:
    build:
      context: .
      dockerfile: Dockerfile.dev
    container_name: uniapp-dev
    ports:
      - "9000:9000"
    develop:
      watch:
        # 源码改动:仅同步进容器,Vite 原生 HMR(保留页面状态)
        - action: sync
          path: ./src
          target: /app/src
        - action: sync
          path: ./index.html
          target: /app/index.html
        # 根目录配置文件改动:需重启 vite(配置无法热加载)
        - action: sync+restart
          path: ./vite.config.ts
          target: /app/vite.config.ts
        # 依赖改动:重建镜像
        - action: rebuild
          path: ./package.json
        - action: rebuild
          path: ./pnpm-lock.yaml
    environment:
      # 后端地址(见 3.3)
      - VITE_SERVER_TARGET=http://host.docker.internal:48080
    extra_hosts:
      - "host.docker.internal:host-gateway"
    stdin_open: true
    tty: true

develop.watch 三种动作的含义

动作 触发时机 效果
sync 源码文件(src/)变化 只把文件同步进容器,Vite 原生 HMR,不重启
sync+restart 配置文件(vite.config.ts 等)变化 同步后重启 vite(配置必须重启才生效)
rebuild package.json / pnpm-lock.yaml 变化 重新构建镜像(依赖变了,要重装)

4.3 .dockerignore

dockerignore 复制代码
node_modules
dist
.git
docs
.image
.husky
.vscode
.github
*.log

排除无关文件,缩小构建上下文、加快构建。


五、第一次启动(初始化)

bash 复制代码
cd yudao-ui-admin-uniapp
docker compose -f docker-compose.dev.yml up --watch

或(项目里已封装好脚本):

bash 复制代码
pnpm dev:docker

首次启动会做三件事:拉基础镜像 → 构建项目镜像(装依赖)→ 启动容器并进入 watch 模式。构建需要几分钟,之后启动就是秒级。

启动成功后,日志出现 vite 的 ready in xxx ms,浏览器访问:

bash 复制代码
http://localhost:9000/admin-ui-uniapp/

注意:命令里的 --watch 不能省,这是热更新的关键(见第七章)。


六、日常开发流程

6.1 每天开工

bash 复制代码
cd yudao-ui-admin-uniapp
pnpm dev:docker

6.2 改代码 → 自动热更新

在 IDE 里正常改 src/ 下的代码,保存即生效:

  • 改组件/页面 → Vite 原生 HMR,毫秒级,保留页面状态(不刷新页面);
  • vite.config.ts 等配置文件 → 自动重启 vite(约 2~5 秒);
  • package.json 依赖 → 自动重建镜像(需要网络)。

6.3 收工

bash 复制代码
# 停止容器(保留镜像和数据,下次秒启)
docker compose -f docker-compose.dev.yml stop
# 或直接 Ctrl+C(up --watch 在前台跑时)

6.4 什么时候需要重建

场景 命令
改代码(日常) 什么都不用做,自动热更新
Dockerfile.dev docker compose -f docker-compose.dev.yml up --watch --build
改 compose 文件 重新 up --watch
改依赖(package.json) 自动 rebuild,或手动 --build

七、热更新:正确姿势与原理(重点)

7.1 症状

Windows + Docker Desktop 下,如果按网上教程用 bind mountvolumes: - .:/app)方式挂源码,改代码后浏览器不刷新,必须重启容器才生效。这是 Windows 上 Docker 跑前端最常见的坑。

7.2 根因

Docker Desktop 在 Windows 上通过 WSL2/Hyper-V 的虚拟文件共享层 把宿主机目录挂进容器。这个共享层不会把宿主机侧的文件变更事件转发进容器------容器内的 Vite/chokidar 收不到"文件变了"的通知,HMR 自然不触发。

bash 复制代码
bind mount 方案:
宿主机改代码 → 文件在宿主机侧变化
                    │
                    ▼
          虚拟文件共享层 ⚠️ 变更事件在这里丢失
                    ▼
        容器内 Vite 收不到通知 → HMR 不触发

7.3 正确方案:COPY + compose watch 的 sync

思路 :不靠 bind mount,改为「源码 COPY 进镜像 + compose watch宿主机侧 监听文件、把改动写进容器」。文件是在容器侧写入的(本地写入),Vite 的原生文件监听能正常收到事件,原生 HMR 即可工作。

bash 复制代码
正确方案:
宿主机改代码
     │  compose watch 在宿主机侧监听(Windows 原生监听,正常)
     ▼
sync 把新文件写进容器(容器侧写入,事件正常)
     ▼
Vite 原生 HMR 检测到变化 → 模块热替换(保留状态,毫秒级)

这就是第四章那份配置的来源Dockerfile.devCOPY . . 打源码,compose 里 srcsync

7.4 为什么必须 up --watch,点 Start 不行

Docker Desktop 的 Start 按钮只是 docker start(拉起容器进程),不会启动 compose watch 的宿主机侧监听会话 。没有 watch 会话就没有 sync,容器里跑的是镜像里的源码快照------你改的代码根本进不了容器,自然不热更新。

启动方式 watch 会话 文件同步 热更新
docker compose up --watch ✅ 有 ✅ sync
Docker Desktop 点 Start ❌ 没有 ❌ 无同步 ❌ 跑的是镜像快照
docker compose up -d(普通后台) ❌ 没有 ❌ 无同步 ❌ 跑的是镜像快照

7.5 为什么不需要 node_modules 命名卷

旧方案(bind mount)必须挂一个 node_modules 命名卷,因为 .:/app 会把宿主机 Windows 的 node_modules 一起挂进来------里面的 .exe 二进制在 Linux 容器里跑不了,得用命名卷把容器里的 Linux 版"盖回来"。

新方案源码是 COPY 进镜像、没有 bind mount,宿主机不会污染容器内的 node_modules,sync 也只同步 ./src,所以命名卷不需要了(还能省几百 MB 磁盘)。

7.6 终极推荐:前端本地跑 + Docker 管基础设施

如果团队不强制"前端也必须在 Docker 里",最佳体验是前端在 Windows 本地原生跑(HMR 毫秒级、无中间层),Docker 只负责 MySQL、Redis、后端:

bash 复制代码
docker compose up -d mysql redis    # 启动基础设施
cd yudao-ui-admin-uniapp
nvm use 20                          # 切 Node 版本
pnpm install
pnpm dev:h5                         # 前端本地跑,改代码即时 HMR
方案 HMR 延迟 页面状态 复杂度
前端本地跑 + Docker 管基础设施 <100ms ✅ 保留 低(推荐)
Docker 跑前端(COPY + sync) 毫秒级 ✅ 保留 中(本文方案)
Docker 跑前端(bind mount) ❌ 不生效 - -

八、常见问题排查

Q1:pnpm install 时报 MODULE_NOT_FOUND: create-base-files.js

原因pnpm install 自动跑 prepare 脚本,但构建时 scripts/ 目录还没拷进镜像。

解决 :加 --ignore-scripts 跳过 prepare 钩子(Dockerfile.dev 里已加)。base 文件会在运行时由 predev 钩子生成(那时源码已进镜像)。

Q2:构建时报 Corepack 下载 pnpm 失败 / 拉镜像超时

原因 :国内网络访问 registry.npmjs.org / Docker Hub 不稳定。

解决 :配镜像加速(见 3.2)。注意:改过 package.jsonDockerfile.dev 会触发重新构建,此时需要网络,确保加速器生效后再构建。

Q3:改代码不热更新(Windows + Docker)

先按优先级排查:

  1. 是不是用 up --watch 启动的? 点 Start 或 up -d 都不会热更新(见 7.4)。
  2. compose 里 src 是不是 sync 如果配成了 sync+restart,会变成全量重启(丢状态、慢 2~5s),改成 sync 就是原生 HMR。
  3. 改的是不是 src/ 下的文件? 配置文件本来就要重启,不算 bug。
  4. 改的内容是不是"有效内容"? 测试热更新时,往 .vue 文件 </style> 之后 append 注释是无效的------那是 SFC 语法外区域,vue 编译器会忽略,编译产物没变化,Vite 自然不会触发 HMR。要验证请在 <script> 里加一行真实代码。

Q4:容器里访问不到宿主机后端

解决 :确认 compose 里有 extra_hosts: - "host.docker.internal:host-gateway",且 VITE_SERVER_TARGET 指向 http://host.docker.internal:48080(后端在宿主机跑时)。

Q5:HMR 有反应,但页面刷成空白 / 状态丢了

原因 :改的文件无法热替换(比如改了 main.ts、路由配置、全局样式),Vite 自动降级为整页刷新,这是正常行为,不是故障。

Q6:Windows 上 nvm useA version argument is required

Windows 用的是 nvm-windows ,它不读 .nvmrc,必须手动传版本号:

powershell 复制代码
nvm use 20
# 或从 .nvmrc 读:
nvm use (Get-Content .nvmrc)

九、Docker Desktop 图形界面日常操作

9.1 查看日志

打开 Docker Desktop → Containers → 点容器 → Logs 标签页。与命令行 docker logs -f 完全等价,显示的是同一份输出。

操作 方法
实时跟踪 点右上角 ▶️ Follow log
筛选关键字 顶部搜索框输入
清屏(不影响后台) 🗑️ Clear

9.2 启停容器

注意:Start/Stop 只适合"临时暂停恢复",不是日常热更新入口。 要让代码同步进容器,必须用 up --watch 启动(见 7.4)。

操作 说明
容器旁 ⏸️ Stop 等价 docker stop,暂停进程,数据保留
容器旁 ▶️ Start 等价 docker start不带 watch,仅恢复进程
彻底删除 docker compose down(保留镜像和数据卷)

9.3 看磁盘占用

bash 复制代码
docker system df

清理无用资源:

bash 复制代码
docker container prune    # 删停止的容器
docker image prune -a     # 删未使用的镜像
docker volume prune       # 删未引用的数据卷

十、快捷命令速查

项目 package.json 里封装了常用命令(以 uniapp 项目为例):

命令 作用 等价命令
pnpm dev:docker 启动开发容器(带 watch) docker compose -f docker-compose.dev.yml up --watch
pnpm dev:docker:stop 停止容器 docker compose -f docker-compose.dev.yml down
pnpm dev:docker:rebuild 重建镜像并启动 docker compose -f docker-compose.dev.yml up --watch --build
pnpm dev:docker:logs 查看日志 docker compose -f docker-compose.dev.yml logs -f

十一、两个项目的配置对照(vue3 / uniapp)

两个项目都已按本文方案配好,差异只在端口、环境变量和 watch 条目:

vue3(yudao-ui-admin-vue3) uniapp(yudao-ui-admin-uniapp)
容器名 qs-vue3-dev uniapp-dev
端口 8081:80 9000:9000
Vite 版本 8.0.10 5.2.8
后端代理变量 VITE_PROXY_TARGET VITE_SERVER_TARGET
watch 的 src sync sync
watch 的配置文件 vite.config.ts / build / .env vite.config.ts / pages.config.ts / manifest.config.ts / uno.config.ts / env
启动命令 pnpm dev:docker pnpm dev:docker
访问地址 http://localhost:8081/ http://localhost:9000/admin-ui-uniapp/

两个项目结论一致:Vite 5 和 Vite 8 的 chokidar 都正常COPY + sync 方案下原生 HMR 都能工作,不需要任何额外脚本。


附录:常用命令速查表

bash 复制代码
# 启动(带 watch,热更新)
docker compose -f docker-compose.dev.yml up --watch

# 停止(保留容器/镜像/数据)
docker compose -f docker-compose.dev.yml stop

# 彻底删除容器(保留镜像和数据卷)
docker compose -f docker-compose.dev.yml down

# 重建镜像并启动(改了 Dockerfile 或依赖)
docker compose -f docker-compose.dev.yml up --watch --build

# 查看日志
docker compose -f docker-compose.dev.yml logs -f <服务名>

# 进入容器
docker exec -it <容器名> sh

# 查看容器状态
docker ps

# 查看磁盘占用
docker system df

# 进入容器调试
docker exec -it uniapp-dev sh

最后提醒一句 :本地开发最顺手的还是"前端本地跑 + Docker 管基础设施";如果团队要求前端也容器化,用本文第四、七章的 COPY + sync 方案即可,两条路都能拿到毫秒级 HMR 和保留页面状态。

相关推荐
fatcoder2 小时前
玩转Docker 08 — 实战:容器化真实后端并编排
后端·docker·容器
vortex54 小时前
Container Desktop 安装与配置指南
docker
江湖有缘6 小时前
5款开源wiki知识库工具,支持Docker快速部署!
docker·容器·开源
云上飞476369628 小时前
Windows WSL2 + Docker 环境下NVIDIA PhysicsNeMo 安装指南
windows·docker·physicsai·physicsnemo
抓不住时间的沙8 小时前
N1搭建Hexo个人博客,部署到Github
python·docker·node.js·debian·github·arm
wsad05329 小时前
CentOS 10 上使用 Docker Compose 部署 Discuz X5.0 论坛完整教程
linux·docker·centos·discuz
BTU_YC20 小时前
Docker Compose 部署 DozerDB 完整教程
运维·docker·容器
spencer_tseng1 天前
[kylin & linux] install docker
linux·docker·kylin
airobotcn1 天前
智能巡检平台容器化部署:Docker+K8s在工业边缘的实践
人工智能·docker·容器·kubernetes·机器人·自动化