phoenixframework / phoenix_live_reload

Provides live-reload functionality for Phoenix
MIT License
317 stars 90 forks source link

Live Reloader and Apps that are not at "/", the server root #83

Closed easco closed 6 years ago

easco commented 6 years ago

Our application in production runs through a proxy with a base URL that is not "/". To emulate that in development environments we run the application under a proxy and use the :path option of the :url config of the endpoint to identify the root path (with appropriate updates to the router, static path locations, etc).

config :my_app, MyAppWeb.Endpoint,
  url: [host: "localhost", path: "/my_app"],

This "breaks" the Phoenix.LiveReloader plug's functionality. At the heart of the breakage is that the LiveReloader creates an iframe and sets the source of that iframe to:

  # from live_reloader.ex:125
  defp reload_assets_tag(conn) do
    path = conn.private.phoenix_endpoint.path("/phoenix/live_reload/frame")
    """
    <iframe src="#{path}" style="display: none;"></iframe>
    """
  end

Because it is using the endpoint information to generate the path, the source of the reload iframe is presumed to be hosted with the non-root path component added (my_app in this case : http://localhost:4000/my_app/phoenix/live_reload/frame)

To provide the content of that frame, however, the live_reloader code does an explicit match on path_info in the connection:

def call(%Plug.Conn{path_info: ["phoenix", "live_reload", "frame"]} = conn , _) do
    # …more stuff here…
end

So it explicitly looks for a request to "/phoenix/live_reload/frame" at the root (it doesn't take the fact that the endpoint might be based somewhere other than root into account). As a result, the content of the frame is not loaded and the live reload functionality breaks down.

To resolve this, either the hard-coded path for the content of the iframe needs to be matched dynamically, and take the endpoint's settings into account, or the path that serves as the src of the iframe needs to not take the endpoint settings into account.

josevalim commented 6 years ago

@easco the path configuration only affects URL generation. It is assuming that you are actually running the service behind a proxy that is yanking the /myapp from it when you access it. So I am afraid that other things will break, unless you have a proxy in front of the application and stripping the /myapp part.

easco commented 6 years ago

FWIW, so far this is the only thing we've run into. The root path does have to be accounted for in the router (we have to take it into account in the scope) and IIRC the lines in the endpoint where we define where static assets are served.

The path on the endpoint, as you point out, DOES affect URL generation as seen in reload_assets_tag above, the logical inconsistency is that the the pattern match that provides the content of the iframe is not also "built in that space" -- it is not also based in that URL generation mechanism.

If you don't care to address this issue, that's fine. We can work with the proxy to try and add rewrite rules in our dev environment for the sake of code reloading – and then in production (should the need arise).

josevalim commented 6 years ago

It is not that we don’t want to fix. It is rather that, if we “fix” it, we will break it for everyone that is using the :path configuration properly.

When accessing a “mounted” application, the path should be stripped by whoever is proxying. If the goal is to have development mirror production, then that’s what should be done. --

José Valimwww.plataformatec.com.br http://www.plataformatec.com.br/Founder and Director of R&D

easco commented 6 years ago

I have the case where my Development mirrors Production.

As I understand your comments, you are saying that Phoenix is only designed to run applications that are hosted at the root path, “/“, of the server they are running on. Is that an accurate statement?

josevalim commented 6 years ago

No. :) you can run Phoenix under /my_app, but the proxy/load balancer should then remove it when invoking your app. This is the typical behavior of proxy/load balancer. --

José Valimwww.plataformatec.com.br http://www.plataformatec.com.br/Founder and Director of R&D