Server render complete hook/event

bjunc
114
bjunc
commented 2 years ago

Is there a way (or could one be added) to listen for an event/hook for when Nuxt is about to return the response to the browser?

The reason being, I'm using sockets server-side. In a browser, the socket will automatically be disconnected on page unload. This doesn't happen server-side, so every new page request leaves orphaned socket connections. Ideally, I'd listen for an event/hook that knew we were finished with the socket, and disconnect. Currently, I'm using setTimeout to disconnect the socket (only for process.server). It works, but it feels dirty, and possibly error prone.

By the way, I've looked into using a module and listening for render:route, but it's unclear if that happens at the appropriate lifecycle point (actual documentation would be helpful here), nor am I aware of how to access the apollo clients from there (which is what I'm using for the socket).

1
qm3ster
383
qm3ster
commented 2 years ago

Why don't you close the socket when you are done with it? Can't you tell it to close once you have the data you need to render the page?

0
bjunc
114
bjunc
commented 2 years ago

@qm3ster not really. Technically, I can disconnect/close the socket connection any time I want, but only if I know I'm actually finished with it. The main benefit of a socket in this context is that nested pages/routes/store actions would all use the same socket connection (cumulatively decreasing the server-side page load pretty considerably). I can't make the assumption that after the parent page's asyncData/fetch, I can now close the connection; since nested pages might need to make further requests. Then there's the possibility that nested pages actually complete their requests before the parent page, so you can't safely rely on an assumed waterfall/sequence.

There isn't currently (that I know of), a reliable way to know that all components are finished rendering, which would essentially mean we're finished with the socket connection. I've had to resort to an explicit timeout, which works, but feels dirty. In affect, I am asking for a "tear down" event (not for the Node server, but for the request/response).

0
qm3ster
383
qm3ster
commented 2 years ago

Making essentially a WaitGroup on the object you're using to pass the socket reference around might be a non-dirty way to do it without hooks.

But I do see the general purpose need for such a hook to clean up resources when all components have executed and returned. I'll look into it.

0
bjunc
114
bjunc
commented 2 years ago

As an experiment, I added a new hook called render:routeDone, and passed the renderer context. I called this right before the return in renderRoute (nuxt/lib/core/renderer.js). In my Apollo client config, I assigned the underlying socket to ctx.req.socket, which I then had access to in a tear down plugin listening for the new render:routeDone hook. With this, I was able to disconnect the socket.

So basically, I got it working, but I had to add my own hook, and I'm not sure this is the "best" way of handling this (in that, is it extensible / applicable to other use-cases for tear down).

Thoughts?

0
qm3ster
383
qm3ster
commented 2 years ago

Seems like that would call multiple times for nuxt generate.
Furthermore, shouldn't you return the rendered page first and then do cleanup, to optimize the critical path?
Where do you open your socket?

0
bjunc
114
bjunc
commented a year ago

@manniL I think this is still relevant. Knowing when Nuxt has completed a response is an important lifecycle event. Doing per-request tear-down (eg. for sockets) has been problematic, and has to use things like timeouts, etc..

Is there a way to know when a response has been sent to the browser within Nuxt?

0
manniL
6.4k
manniL
commented a year ago

@bjunc There is no built-in (server-side) hook for this by now. The only event is client-side and is called routeChanged.

I'm sure a PR would be great (If you want to share you render:routeDone hook) ☺️

0
Informations
QuestionUnresolved
#c2503 - Created 2 years ago