Phoenix Live Reload for API

Hello everyone,

I am trying to implement live reload on a static page, for an API.

I build the project with --no-html --no-webpack, and added a bucklescript pipeline instead.

There is only one page, a static index.html, located in priv/static. I render with the following action

  def index(conn, _params) do
    conn
    |> put_resp_header("content-type", "text/html; charset=utf-8")
    |> IO.inspect()
    |> send_file(200, "priv/static/index.html")
  end

I added phoenix-live-reload, configured the api to use it… and now code is reloading when frontend files change. I can see bsb and webpack reloading in the background.

I have configured my Endpoint with live/code reload, and I can see in my connection when in development.

  before_send: [#Function<1.112466771/1 in Plug.Logger.call/2>, 
   #Function<0.66982185/1 in Phoenix.LiveReloader.before_send_inject_reloader/2>],

But as it is an api only, there is no phoenix_html, I need to inject the live reload iframe manually into the static index.html.

Can somebody point me where (and when) Phoenix inject the live reload iframe? I find it hard to find in the source code.

Thanks for taking time

2 Likes

Here:

2 Likes

Thank You for the response, but I read this and configured accordingly…

It does set the before_send in my connection correctly.

But I would like to know where this function is applied in reality (the plug just add a function in the before_send). As it is a static file, not an eex template, I will need to inject manually.

1 Like

The code is in the live_reloader, as said by @dom, in the private functions…

At the very end, we can find

  defp before_send_inject_reloader(conn, endpoint) do
    register_before_send(conn, fn conn ->
      if conn.resp_body != nil && 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 <> reload_assets_tag(conn) <> Enum.join(["</body>" | rest], "")
          put_in conn.resp_body, body
        else
          conn
        end
      else
        conn
      end
    end)
  end

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

The solution is dead simple (once You get how it works), Not even the need to parse the static file, just render with.

  def index(conn, _params) do
    file = "priv/static/index.html"
    {:ok, binary} = File.read(file)
    html(conn, binary)
  end

The html helper will take care of this. Sorry for the question…

Now I have a slim api, with live reload enable on the static file.

2 Likes