Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Phoenix: how to serve a Single Page App

I want to set Phoenix up to serve a static index.html no matter what route is sent to it, without changing the URL and while providing access to non-html assets (.js, .css, .jpg,...), as my SPA (in Elm) will look at the route and work out what to do.

Based on this and this I have tried the following, but without success

endpoint.ex

  plug Plug.Static,
    at: "/", from: :mosaic_api, gzip: false,
    only: ~w(assets css fonts images js favicon.ico robots.txt index.html)

router.ex

  scope "/", Api do
    pipe_through :browser # Use the default browser stack
    get "/*path", PageController, :index  # :elm
  end

PageController.ex

defmodule Api.PageController do
  use Api.Web, :controller

  plug :action  # Edit: now removed

  def index(conn, _params) do
    conn
    |> put_layout(false)
    |> render("index.html")
    # Edit: replaced 3 lines above by: html(conn, File.read!("priv/static/index.html"))
  end

  def elm(conn, _params) do
      redirect conn, to: "/index.html"
  end
end

With :index I get a Phoenix-related (but not the standard home-) page and a console error (Plug.Conn.AlreadySentError) the response was already sent, while with :elm I end up at /index.html and have lost the routing information.

like image 327
Simon H Avatar asked Oct 19 '22 08:10

Simon H


1 Answers

only: ~w(... index.html)

conn
|> put_layout(false)
|> render("index.html")

It seems you try to render the static index.html that's not work. The put_layout/2 disable or change the wrapper layout. render/2 set the file to use as content. Default this file located at /web/templates/MODULE/.

You can use the Phoenix.Controller.html/2 function for send custom html content. Read the the file with File.read!/2 and send the content to the client.

def index(conn, _params) do
  html(conn, File.read!("priv/static/index.html"))
end

I'm not sure if there an other cleaner solution but this should work. Hope this helps.

EDIT:

Solve the AlreadySentError by remove the plug :action from your controller. It is called automatically since version 0.14.0.

See these 0.13.x to 0.14.0 upgrade instructions to bring your existing apps up to speed.

  • Backward incompatible changes
    • [Controller] plug :action is now called automatically
like image 198
Fabi755 Avatar answered Oct 21 '22 22:10

Fabi755