C-0912
@C-0912 (C-)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

NestJS Docker HMR is not working

NestJS Docker HMR is not working

問題点

NestJSをDockerに載せて動かす時、HMRやlive reloadなどが動かない

解決策

まだわかっていない。
この件についてまるで分からないので分かる方教えて頂けると幸いです。

内容

Dockerfile

Dockerfile
FROM node:20.12.0
RUN npm i -g @nestjs/cli
WORKDIR /app

COPY package.json package-lock.json ./

RUN npm ci

COPY . .

CMD [ "npm", "run", "docker:init" ]

docker-compose.yml

docker-compose.yml
version: '3.8'
services:
  api:
    container_name: api
    build: .
    tty: true
    ports:
      - '3000:3000'
    volumes:
      - type: bind
        source: .
        target: /api
    env_file:
      - config/.env
    depends_on:
      mysql:
        condition: service_healthy
  mysql:
    container_name: mysql
    image: mysql:8
    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --default-authentication-plugin=caching_sha2_password
    ports:
      - '3306:3306'
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: database
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    volumes:
      - ./mysql_data:/var/lib/mysql
      - ./mysql-init.sql:/docker-entrypoint-initdb.d/mysql-init.sql
    healthcheck:
      test: ['CMD', 'mysqladmin', 'ping', '-h', 'localhost']
      interval: 10s
      timeout: 5s
      retries: 5

.dockerignore

.dockerignore
node_modules
dist
mysql_data

package.json

package.json
"script": {
  "docker:init": "npm run prisma:migrate && npm run prisma:generate && npm run start:dev"
]

試したこと

公式に記載されていること

hot-reload in NestJS Doc

  1. 必要パッケージのインストール
terminal
npm i --save-dev webpack-node-externals run-script-webpack-plugin webpack
  1. webpack-hmr.config.jsの作成
webpack-hmr.config.js
const nodeExternals = require('webpack-node-externals');
const { RunScriptWebpackPlugin } = require('run-script-webpack-plugin');

module.exports = function (options, webpack) {
  return {
    ...options,
    entry: ['webpack/hot/poll?100', options.entry],
    externals: [
      nodeExternals({
        allowlist: ['webpack/hot/poll?100'],
      }),
    ],
    plugins: [
      ...options.plugins,
      new webpack.HotModuleReplacementPlugin(),
      new webpack.WatchIgnorePlugin({
        paths: [/\.js$/, /\.d\.ts$/],
      }),
      new RunScriptWebpackPlugin({ name: options.output.filename, autoRestart: false }),
    ],
  };
};

をルートディレクトリに追加

  1. package.jsonに下記を追加
package.json
"start:dev": "nest build --webpack --webpackPath webpack-hmr.config.js --watch"
  1. main.tsの変更
    module.hotの定義が無かった為、@types/webpack-envをインストールした。
    -> 無事、型定義エラーは消えた
main.ts
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);

  // 下記追記
+  if (module.hot) {
+    module.hot.accept();
+    module.hot.dispose(() => app.close());
  }
}
bootstrap();

この状態で、docker compose upして起動は確認できた。
webpack 5.90.1 compiled successfully in 1851 ms

その他試した事

webpack-hmr.config.js

上記のwebpack-hmr.config.jsを下記の様に変更した

webpack-hmr.config.js
const nodeExternals = require('webpack-node-externals');
const { RunScriptWebpackPlugin } = require('run-script-webpack-plugin');

module.exports = function (options, webpack) {
  return {
    ...options,
    entry: ['webpack/hot/poll?100', options.entry],
    externals: [
      nodeExternals({
        allowlist: ['webpack/hot/poll?100'],
      }),
    ],
    plugins: [
      ...options.plugins,
      new webpack.HotModuleReplacementPlugin(),
      // WatchIgnorePluginは削除、または無視するパスを限定
      new webpack.WatchIgnorePlugin({
-        paths: [/\.js$/, /\.d\.ts$/],
+        paths: [/\.d\.ts$/], // .d.tsファイルのみ無視
      }),
      new RunScriptWebpackPlugin({
        name: options.output.filename,
-       autoRestart: false
+       autoRestart: true, // HMRで再起動するように設定
      }),
    ],
  };
};

docker-compose.yml

volumesの箇所を変更した

docker-compose.yml
volumes:
      - type: bind
        source: .
        target: /api
+      - /api/node_modules
docker-compose.yml
volumes:
      - type: bind
        source: .
        target: /api
+      - .:/app
+      - /api/node_modules

tsconfig.jsonの変更

GitHub Issue

以上のIssueから

tsconfig.json
+ "watchOptions": {
+    "watchFile": "fixedPollingInterval"
+  }

portチェック

main.ts
 await app.listen(3000)
docker-compose.yml
 ports:
      - '3000:3000'

合っているから問題なさそう

推論

webpack-hmr.config.jsなどを導入し起動した際、
webpack 5.90.1 compiled successfully in 1851 ms
の表示と共にAPIリストなど出力されて起動は確認できた。

コードの変更検知->Docker変更認知

変更検知からDocker変更認知の辺りで上手くかみ合ってないと思っている。
何が正しいかもわかっていませんが…

tsc --watchを入れて動かすとまた違うのか?
Dockerも詳しくないし、ここら辺の仕組みがまるで分からない。。。

React Vite on Dockerの環境では、HMRを動かすことに成功したが、NestJSはまるでわからん。
docker-compose.yml

docker-compose.yml
volumes:
      - type: bind
        source: .
        target: /api
+      - .:/app
+      - /api/node_modules

のような感じでvolumesにソースコードを渡してやったら出来たり、

vite.config.ts
export default defineConfig({
  plugins: [react(), vanillaExtractPlugin()],
  server: {
    host: '0.0.0.0',
    port: 3000,
    hmr: true,
    watch: {
      usePolling: true,
    },
  },
})

と記載したら出来た。
host, portは問題ないはず
watch-pollingやhmrの起動辺りのオプションだったりがNestJSにもあると思われる。

Dockerに載せるようになってまるで分からない
Dockerへの理解がまるでないからきっとそこに原因はありそうな気がするけれど。。。

どなたか同様の問題で解決方法を知っていれば教えて頂けると幸いです。

0

1Answer

試していませんが、 Stack Overflow の同様の質問にいくつか解決策が提示されています。

0Like

Your answer might help someone💌