[未解決] NestJS Docker HMR
NestJS Docker HMR is not working
問題点
NestJSをDockerに載せて動かす時、HMRやlive reloadなどが動かない
解決策
まだわかっていない。
この件についてまるで分からないので分かる方教えて頂けると幸いです。
内容
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
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
node_modules
dist
mysql_data
package.json
"script": {
"docker:init": "npm run prisma:migrate && npm run prisma:generate && npm run start:dev"
]
試したこと
公式に記載されていること
- 必要パッケージのインストール
npm i --save-dev webpack-node-externals run-script-webpack-plugin webpack
-
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 }),
],
};
};
をルートディレクトリに追加
-
package.json
に下記を追加
"start:dev": "nest build --webpack --webpackPath webpack-hmr.config.js --watch"
-
main.ts
の変更
module.hotの定義が無かった為、@types/webpack-env
をインストールした。
-> 無事、型定義エラーは消えた
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
を下記の様に変更した
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の箇所を変更した
volumes:
- type: bind
source: .
target: /api
+ - /api/node_modules
volumes:
- type: bind
source: .
target: /api
+ - .:/app
+ - /api/node_modules
tsconfig.jsonの変更
以上のIssueから
+ "watchOptions": {
+ "watchFile": "fixedPollingInterval"
+ }
portチェック
await app.listen(3000)
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
に
volumes:
- type: bind
source: .
target: /api
+ - .:/app
+ - /api/node_modules
のような感じでvolumesにソースコードを渡してやったら出来たり、
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への理解がまるでないからきっとそこに原因はありそうな気がするけれど。。。
どなたか同様の問題で解決方法を知っていれば教えて頂けると幸いです。
追記
環境を用意してdocker compose up --watch
を行ったところ、bcryptのエラーが出た
Error: /app/node_modules/bcrypt/lib/binding/napi-v3/bcrypt_lib.node: invalid ELF header
似たような形できっとdayjsも出てくるのだろうと思いながら進捗はストップ
過去にもこれが出てきて、分からずに他人にヘルプを出したが、今回もそうなりそう。
何が原因で何がだめなのかが全く分からない。
ここに書いてある原因としてコンパイルアーキテクチャが違うから?
やってみたこと
volumes:
- type: bind
source: .
target: /api
- .:/app
- - /api/node_modules
node_modulesを渡すのをやめてみた
結果、相変わらずだった
OS由来やコンパイルアーキテクチャがどうのこうのと言われても全く知らないので、何となく違うんだろうなとしか思えず良い案が出てこない。。。
毎度、綺麗な解決方法を知らないし原因が具体的にどういうものなのかも掴めてないのがつらい。
Discussion
手元で Nest.js アプリの HMR は Docker コンテナーでも動作しています。確認したときの内容を記事にしてありますので、よろしかったら、ご覧ください。
こちらは Ubuntu 22.04 環境なのですが、使われている OS が Windows でも、記事で紹介している Compose Watch 機能で解決しそうな気がします。
コメントありがとうございます!
Watch機能、完全に意識から漏れてました。。。
一度チャレンジしてまた何か進展があれば追記させていただきます!
ご教示いただきありがとうございます。