vavite
vavite copied to clipboard
Reloading causes Nestjs double injects
Hi,
I noticed that when you change something your Injectable()
sevice get's reloaded, but the old one isn't removed.
causing multiple instances of services.
The following case shows this: https://stackblitz.com/edit/github-bm1t8n?file=server%2Ftask.service.ts
when you clone the project, it should startup directly and the log should start showing:
[Nest] 18 - 04/03/2024, 11:05:00 DEBUG [TasksService] Called when the current second is 5
[Nest] 18 - 04/03/2024, 11:05:05 DEBUG [TasksService] Called when the current second is 5
Now change the debug message (without stopping the server)
Now the output is:
[Nest] 32 - 04/03/2024, 11:05:50 DEBUG [TasksService] Called when the current second is 5
[Nest] 32 - 04/03/2024, 11:05:50 DEBUG [TasksService] Called when second is 5
[Nest] 32 - 04/03/2024, 11:05:55 DEBUG [TasksService] Called when second is 5
[Nest] 32 - 04/03/2024, 11:05:55 DEBUG [TasksService] Called when the current second is 5
[Nest] 32 - 04/03/2024, 11:06:00 DEBUG [TasksService] Called when second is 5
[Nest] 32 - 04/03/2024, 11:06:00 DEBUG [TasksService] Called when the current second is 5
I was looking if I could configure to do a full reload instead of a HMR. but couldn't find any way. any suggestions on how to workaround / disable HMR would be fine.
Right now I have to restart the server everytime.
I understand the problem and I have a vague idea why it might be happening (NestJS is probably holding some global state that needs to be reset when certain files are reloaded). But my NestJS knowledge is limited at best and the NestJS example was a community contribution.
I've added a "help wanted" label, let's hope someone can lend a hand.
Thanks for the update, I looked at the issue from a different side: What if the module is correct and Nestjs needs some configuration to support HMR. And I stumbled upon the HMR from nestjs' side, and this might be the key on the error: https://docs.nestjs.com/recipes/hot-reload
They use the following code for the HMR:
declare const module: any;
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();
So the accpt and dispose might be causing the issue, vite's way is with the import.meta.hot
object,
however this is always undefined on my side (and not logging anything on a update)
I've updated the example: https://stackblitz.com/edit/github-bm1t8n?file=server%2Fmain.ts
Unfortunately Vite's ssrLoadModule
that vavite uses under the hood doesn't have HMR support. So import.meta.hot
will always be undefined
on the server.
The new Vite runtime does have support but I think it requires some setup and I didn't have the time to give it a proper look.
But it can be simulated using global variables. Maybe something like this:
async function bootstrap() {
if ((global as any).__app) {
(global as any).__app.close();
}
const (global as any).__app = await NestFactory.create(AppModule);
await (global as any).__app.listen(3000);
}
And maybe we could also wrap this to run on dev only.
Oh nice find, and it works now, thanks! UPDATE: it doens't always work, sometimes it doesn't work, but it's still better than before.
You can ping me if the new vite runtime is out of experimental, I'll check if it works then :)
UPDATE: using
vavite({
serverEntry: './src/server/main.ts',
serveClientAssetsInDev: true,
useViteRuntime: true, <--- this one
}),
Now seems to work :)