Closed krainboltgreene closed 6 months ago
Okay so I've done some deeper digging. I had a hypothesis: Perhaps the chan.join()
isn't firing? The only way to prove that it was actually firing was to utilize a socket constraint in the phoenix.js
library that stops you from double joining. After some hacking I duplicated the chan.join()
line and there was an error!
So somewhere in my browser a channel is being joined for the purposes of the constraint, but not joining for the purposes of sending the message.
I found this interesting tidbit about websockets in iframes: https://stackoverflow.com/a/47900288
Okay, so I can't tell you why this works, but I've rewritten the plug to just shove the js directly into body, instead of via an iframe, and now it works 100%:
defmodule Reloader do
import Plug.Conn
@behaviour Plug
def init(opts) do
opts
end
def call(conn, _) do
endpoint = conn.private.phoenix_endpoint
config = endpoint.config(:live_reload)
patterns = config[:patterns]
if patterns && patterns != [] do
before_send_inject_reloader(conn, endpoint, config)
else
conn
end
end
defp before_send_inject_reloader(conn, endpoint, config) do
register_before_send(conn, fn conn ->
if conn.resp_body != nil and html?(conn) do
resp_body = IO.iodata_to_binary(conn.resp_body)
if has_body?(resp_body) and :code.is_loaded(endpoint) do
[page | rest] = String.split(resp_body, "</body>")
body = [page, inject_reload_sript(conn, endpoint, config), "</body>" | rest]
put_in(conn.resp_body, body)
else
conn
end
else
conn
end
end)
end
defp html?(conn) do
case get_resp_header(conn, "content-type") do
[] -> false
[type | _] -> String.starts_with?(type, "text/html")
end
end
defp has_body?(resp_body), do: String.contains?(resp_body, "<body")
defp inject_reload_sript(conn, endpoint, config) do
IO.iodata_to_binary(["""
<script type="application/javascript">#{read_external_javascript(:phoenix, "priv/static/phoenix.js")}</script>
<script type="application/javascript">
var socket = new Phoenix.Socket("/phoenix/live_reload/socket");
var interval = 100;
var targetWindow = "top";
#{read_external_javascript(:phoenix_live_reload, "priv/static/phoenix_live_reload.js")}
</script>
"""])
end
defp read_external_javascript(application, file) do
Application.app_dir(application, file)
|> File.read!
|> String.replace("//# sourceMappingURL=", "// ")
end
end
I'm at wits end with this issue, because I have done a ton of digging. Here are the two facts that I know:
phoenix:live_reload
.I have confirmed that:
I am in a unique situation however, in that my application is running on Github Codespaces. I'm not accessing my application at
localhost:4000
, but rather a unique URL github assigns my application.Some things that are different between the two page loads: