You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nest.js Docker镜像热重载失效问题排查求助

Nest.js Docker开发环境热重载失效问题排查与修复

问题描述

我按照教程配置了Nest.js项目的Dockerfile、docker-compose.yml及package.json,使用node:18-alpine镜像构建开发环境,已将本地目录挂载到容器,执行npm run start:dev启动服务。本地文件修改后可同步到容器内,但Nest.js的热重载未触发,怀疑与TypeScript或Nest版本有关。

配置文件

Dockerfile

###################
# BUILD FOR LOCAL DEVELOPMENT
###################

FROM node:18-alpine As development

# Create app directory
WORKDIR /usr/src/app

# Copy application dependency manifests to the container image.
# A wildcard is used to ensure copying both package.json AND package-lock.json (when available).
# Copying this first prevents re-running npm install on every code change.
COPY --chown=node:node package*.json ./

# Install app dependencies using the `npm ci` command instead of `npm install`
RUN npm ci

# Bundle app source
COPY --chown=node:node . .

# Use the node user from the image (instead of the root user)
USER node

###################
# BUILD FOR PRODUCTION
###################

FROM node:18-alpine As build

WORKDIR /usr/src/app

COPY --chown=node:node package*.json ./

# In order to run `npm run build` we need access to the Nest CLI.
# The Nest CLI is a dev dependency,
# In the previous development stage we ran `npm ci` which installed all dependencies.
# So we can copy over the node_modules directory from the development image into this build image.
COPY --chown=node:node --from=development /usr/src/app/node_modules ./node_modules

COPY --chown=node:node . .

# Run the build command which creates the production bundle
RUN npm run build

# Set NODE_ENV environment variable
ENV NODE_ENV production

# Running `npm ci` removes the existing node_modules directory.
# Passing in --only=production ensures that only the production dependencies are installed.
# This ensures that the node_modules directory is as optimized as possible.
RUN npm ci --only=production && npm cache clean --force

USER node

###################
# PRODUCTION
###################

FROM node:18-alpine As production

# Copy the bundled code from the build stage to the production image
COPY --chown=node:node --from=build /usr/src/app/node_modules ./node_modules
COPY --chown=node:node --from=build /usr/src/app/dist ./dist

# Start the server using the production build
CMD [ "node", "dist/main.js" ]

docker-compose.yml

version: "3.9"
services:
  nest_app:
    container_name: nest_app
    build:
      context: .
      dockerfile: Dockerfile
      # Only will build development stage from our dockerfile
      target: development
      args:
        - NEST_APP_PORT=${NEST_APP_PORT}
    volumes:
      - .:/usr/src/app
    # Run a command against the development stage of the image
    command: npm run start:dev
    ports:
      - '${NEST_APP_PORT}:${NEST_APP_PORT}'
    networks:
      - nest_try_2
networks:
  nest_try_2:
    driver: bridge

package.json

{
  "name": "nest_try_2",
  "version": "0.0.1",
  "description": "",
  "author": "",
  "private": true,
  "license": "UNLICENSED",
  "scripts": {
      "build": "nest build",
      "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
      "start": "nest start",
      "start:dev": "nest start --watch",
      "start:debug": "nest start --debug --watch",
      "start:prod": "node dist/main",
      "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
      "test": "jest",
      "test:watch": "jest --watch",
      "test:cov": "jest --coverage",
      "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
      "test:e2e": "jest --config ./test/jest-e2e.json"
  },
  "dependencies": {
      "@nestjs/common": "^9.0.0",
      "@nestjs/core": "^9.0.0",
      "@nestjs/platform-express": "^9.0.0",
      "reflect-metadata": "^0.1.13",
      "rxjs": "^7.2.0"
  },
  "devDependencies": {
      "@nestjs/cli": "^9.0.0",
      "@nestjs/schematics": "^9.0.0",
      "@nestjs/testing": "^9.0.0",
      "@types/express": "^4.17.13",
      "@types/jest": "29.5.1",
      "@types/node": "18.16.12",
      "@types/supertest": "^2.0.11",
      "@typescript-eslint/eslint-plugin": "^5.0.0",
      "@typescript-eslint/parser": "^5.0.0",
      "eslint": "^8.0.1",
      "eslint-config-prettier": "^8.3.0",
      "eslint-plugin-prettier": "^4.0.0",
      "jest": "29.5.0",
      "prettier": "^2.3.2",
      "source-map-support": "^0.5.20",
      "supertest": "^6.1.3",
      "ts-jest": "29.1.0",
      "ts-loader": "^9.2.3",
      "ts-node": "^10.0.0",
      "tsconfig-paths": "4.2.0",
      "typescript": "^5.0.0"
  },
  "jest": {
      "moduleFileExtensions": [
      "js",
      "json",
      "ts"
      ],
      "rootDir": "src",
      "testRegex": ".*\\.spec\\.ts$",
      "transform": {
      "^.+\\.(t|j)s$": "ts-jest"
      },
      "collectCoverageFrom": [
      "**/*.(t|j)s"
      ],
      "coverageDirectory": "../coverage",
      "testEnvironment": "node"
  }
}

修复方案

1. 避免Volumes覆盖容器内的node_modules

本地目录挂载会覆盖容器内的node_modules,导致热重载依赖的库(如chokidar)丢失或版本不兼容。修改docker-compose.yml的volumes配置,保留容器内的node_modules:

volumes:
  - .:/usr/src/app
  - /usr/src/app/node_modules

2. 启用文件轮询监听(适配Alpine镜像)

Alpine的musl libc可能导致chokidar无法正常检测文件变化,强制使用轮询模式:

  • 修改package.json的启动脚本:
"start:dev": "nest start --watch --watchOptions \"{\\\"usePolling\\\": true}\""
  • 或者直接在docker-compose.yml中修改command:
command: npm run start:dev -- --watchOptions '{"usePolling": true}'

3. 调整TypeScript版本兼容性

Nest 9.x对TypeScript 5.x的支持从9.3版本开始,当前使用的Nest 9.0.0可能存在兼容性问题。将TypeScript版本降级到4.9.x:
修改package.json的devDependencies:

"typescript": "^4.9.5"

然后重新构建镜像:

docker-compose build

4. 确认文件权限

确保容器内的node用户对挂载目录有读写权限,可在docker-compose.yml中明确指定用户:

user: "node"

内容的提问来源于stack exchange,提问作者GianPierre Gálvez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 02:24:56