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
相关产品推荐
相关产品推荐

