mszmurlo
mszmurlo

Reputation: 1339

Serving static html (and others) from / in Phoenix Framework

I'm working on an API server implemented with the Phoenix Framework. JSON APIs are served from the /api/<version> URL. The server also needs to serve static .html (and others, .css, .js, etc.) files from / : it's actually a little SPA developed in another language and compiled down to HTML5, JS and CSS. The behavior should be:

The project is generated with mix phx.new --no-ecto --no-html --no-gettext --no-webpack static to get rid of .css, .js files and of the templates. I also created a priv/static directory for the statics assets.

I had to remove only: ~w(css fonts images js favicon.ico robots.txt) from the parameter list of plug Plug.Static in endpoint.ex to have files at the root URL being served. All works fine except the errors:

Here are the two configurations I tried:

Conf I

# endpoint.ex
...
  # Serve at "/" the static files from "priv/static" directory.
  plug Plug.Static.IndexHtml, at: "/"
  plug Plug.Static,
    at: "/",
    from: :static,
    gzip: false
    # only: ~w(css fonts images js favicon.ico robots.txt)
...

Conf II

I removed every thing concerning static content from endpoint.ex and added a static pipeline in router.ex

# router.ex
...
  pipeline :static do
    plug :put_secure_browser_headers
    plug Plug.Static,
      at: "/",
      from: :static,
      gzip: false # ,
      # only: ~w(css fonts images js favicon.ico robots.txt)
    plug :not_found
  end
  
  scope "/", staticWeb do
    pipe_through :static
  end

  def not_found(conn, _) do
    send_resp(conn, 404, "not found")
  end
...

Any hint would be helpful.

Update on 13th of August 2020

Added a catch all rule on scope "/" at the end of router.ex and at least I get a 404 for any wrong request. I'm just wondering how clean all this is...

# router.ex
...
  scope "/", AlaaarmWeb do
    match :*, "/*path", DefController, :error_404
  end

Upvotes: 2

Views: 1963

Answers (1)

Massimiliano
Massimiliano

Reputation: 665

I had your same problem, I was trying to serve a SPA created using create-react-app, and I put all the generated files in the priv/static folder.

The only way I find to serve the static index.html file from the root path is the following:

  • I had to remove the only: option form the Static.Plug in the endpoint.ex file as you did.
  • Following this answer: https://stackoverflow.com/a/37568770/8620481, I adopted a different strategy. Instead of trying to serve the static file directly, I read its content as a string and then serve it from a controller.

In particular, in the router.ex file, under the "/" scope, I have the following route defined:

get "/", PageController, :index

In the PageController, I implemented the index method as follows:

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

I don't know exaclty what is the mechanic behind the Static Plug, but I found this workaround acceptable for my use case.

I hope this could help you as well.

Upvotes: 2

Related Questions