vavite icon indicating copy to clipboard operation
vavite copied to clipboard

Reloading causes Nestjs double injects

Open cskiwi opened this issue 11 months ago • 5 comments

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.

cskiwi avatar Mar 04 '24 10:03 cskiwi

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.

cyco130 avatar Mar 09 '24 09:03 cyco130

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

cskiwi avatar Mar 09 '24 10:03 cskiwi

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.

cyco130 avatar Mar 09 '24 16:03 cyco130

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 :)

cskiwi avatar Mar 10 '24 10:03 cskiwi

UPDATE: using

vavite({
  serverEntry: './src/server/main.ts',
  serveClientAssetsInDev: true,
  useViteRuntime: true, <--- this one
}),

Now seems to work :)

cskiwi avatar Apr 06 '24 11:04 cskiwi