I’ve installed LiveView into an existing Phoenix project (originally created on Phoenix 1.4.16) following this guide. I’m currently working on a LiveView that’s rendered directly in my router: i.e. live "/url", LiveViewModule. I’ve added a regex for this source file to my live_reload config in dev.exs, and I see the [debug] Live reload logline when I make changes to this file.
However, the LiveReload socket for this page gets disconnected immediately after the page loads. In Chrome, the socket to ws://localhost:4000/phoenix/live_reload/socket/websocket?vsn=2.0.0 errors with “WebSocket is closed before the connection is established.”
This only happens on this live route; other views (rendered through get routes and normal controllers and views) live-reload fine.
How might I go about debugging the LiveReload socket and why it’s getting disconnected on live routes?
If not you can try to generate a new Phoenix application with --live (the guide you linked has the command) and compare the generated files with the ones in your project. That’d be app/js, Endpoint, dev config, Plug.Session config and a few main others.
Ran into this issue today. By any chance, is the app.js<script> tag that connects your LiveView socket outside the <head> tag? Mine was, and live_reload wasn’t working on my live routes. Stuck the app script tag back inside <head> and live_reload is working as expected.
EDIT: Nope. I am mistaken. live_reload was working because the LiveView socket wasn’t correctly connecting. Definitely seeing this issue in an existing app, but not in a newly generated app (and have gone through all the relevant files I can think of).
The data-phx-main element (which as far as I can tell is injected by LiveView itself?) is getting inserted before the <!DOCTYPE html> and everything else in my layout, which causes Safari and Chrome at least to mis-parse the rest of the doc such that the live_reload iframe doesn’t get added to the DOM (i.e. document.getElementsByTagName('iframe') returns a blank list).
Oh, man. Nice catch @feifan. I had noticed that <div>, but I didn’t pay attention to its placement.
I’m also getting some weird markup. My <head> tag is now empty, and that inserted <div data-phx-main ...> is the first tag inside the <body>, with the rest of the <head> elements moved inside the <body> tag.
I notice that is not occurring in a freshly generated liveview app, so now I need to hunt down what is screwing up the HTML source.
EDIT: Okay, looks like I got it working. I had to add plug :put_root_layout into the pipeline, and it stopped screwing up the markup and connected both my LiveView and the live_reload socket.
Update: Correct markup also results from specifying a layout on the live route itself, without using plug :put_root_layout. Bad markup seems to only occur when there is no root or route-specific layout specified in the router, and the layout is specified on the LiveView module itself.
Sorry for the delay here, just getting back to this part of my project
Yes that’s absolutely right! I noticed the same thing in my project and setting a root layout fixed it. Thanks for digging into that.
Re
I’m also getting some weird markup. My <head> tag is now empty, and that inserted <div data-phx-main ...> is the first tag inside the <body> , with the rest of the <head> elements moved inside the <body> tag.
That’s because you’re probably looking at the Elements browser inspect, which shows the parsed DOM tree that the browser comes up with. If you actually right-click-view-source (or cURL your endpoint) you’d have seen the HTML I had in my screenshot, which the browser did its best to parse (apparently by assuming that the entire response is body, then adding an empty <head> to make it a valid page in-browser).