Documentation on LiveViews using distinct pids for the dead/live mounts

Hi folks! If you work with LiveView for a while, you already know that the mount/3 callback is called twice: the first time for the dead mount and the second time for the live mount. However, something surprised me the other day: those are handled by two different processes!!! You can check this by running this during mount:

IO.inspect(self(), label: "CONNECTED? #{connected?(socket)}")

For some reason, I never paid enough attention to that, which is shocking considering I have been working with LiveView for many years. TBH, I don’t know why I expected otherwise, but I also don’t remember reading something explicitly mentioning it in the docs before; except for these two sentences:

After rendering the static page, LiveView connects from the client to the server where stateful views are spawned to push rendered updates to the browser, and receive client events via phx- bindings. Just like the first rendering, mount/3, is invoked with params, session, and socket state. However in the connected client case, a LiveView process is spawned on the server, runs handle_params/3 again and then pushes the result of render/1 to the client and continues on for the duration of the connection

Useful for checking the connectivity status when mounting the view. For example, on initial page render, the view is mounted statically, rendered, and the HTML is sent to the client. Once the client connects to the server, a LiveView is then spawned and mounted statefully within a process.

It’s clear to me now that I overlooked the docs, considering that I can clearly read spawn mentioned in both sentences, but I wonder if this is still too subtle.

I learned this the hard way two times this week already, the first time by passing the LiveView pid on start_link to a named GenServer, which made my server hold on to a dead pid while it was running. The second time was a linked GenServer crash that was not terminating the LiveView except when trapping exists :laughing:.

I want to leave this here for posterity so other people don’t lose their sanity trying to understand how this works, but I wonder if we could also make docs a tiny bit more explicit about this so others don’t fall into the same trap :see_no_evil: .

6 Likes