Hey ya’ll! I’m building a single-page app backed by a Phoenix API. I don’t think I need phoenix_html
so I did mix phoenix.new --no-html
, but now I’m not sure where to put the single index.html.eex
page which references my CSS and JS.
- I don’t think I can put it under
web/static/assets
because it’s not a static file. I think I need EEx and <%= static_path() %>
(which comes from the router, not phoenix_html) to reference my CSS and JS, which have dynamic filenames like /js/app-2bb77dbddd1cfc28bc67e5ed3fbdd289.js
- If I put it under
web/templates/page
I get an error: (RuntimeError) Could not load Phoenix.HTML.Engine to use with .html.eex templates.
That error makes it sound like all .eex
templates require the phoenix_html
dependency, even if I’m not using any of its HTML helpers.
What am I missing? Again, I’ve got a JSON API that just needs a mostly-static HTML page to reference my CSS and JS. Thanks for any help!
2 Likes
IMO, the quickest solution here is to just add phoenix_html
back to your app (or create a new phoenix project, this time without the --no-html
flag). You might need it anyway later for something you don’t foresee. It’s an extra deps, but saves you from the trouble.
That said, you actually can call static_path('js/app.js')
from your router (as long as you keep the import MyApp.Router.Helpers
line on web/web.ex
), load the index.html
file as a string, and somehow inject the result of static_path
to the string (through String.replace
), and use html conn, html_string
to send the resulting string back to the client.
However, I think this approach circumvents the blazingly fast template caching that Phoenix has, though. I have no idea how it would affect the performance.
If I want to build a SPA, I usually built the client as a separate project, say as a Node.js front-end app with React and Webpack. Kind of a hassle, but there’s a lot of boilerplate templates that I can use and it’s not tied with the server’s stack. I haven’t build SPAs with Phoenix though, and if I do I might just go with the phoenix_html
approach to simplify things.
3 Likes
You can’t have an html
file without phoenix_html
unless you do something sort of hacky like Bobby said above.
--no-html
is when you want JSON only. You should either put it back or have your own repository/project for the single page app. I personally thing this is a good approach because every time I see someone put a complex JavaScript app inside their backend it becomes just a mess. Maybe I just really like a clean separation of concerns in projects though.
3 Likes
Thanks for clarifying things Of my 3 options:
- Bring back
phoenix_html
- Render a raw HTML string in the controller with
html(conn, str)
using static_path
there
- Build a separate front-end app
I’ll probably go with 1 for now but I am interested in benchmarking 2. phoenix_html
isn’t a large library, but I would rather not pay the memory overhead of including it, so long as it’s not offset by losing the efficiency of Phoenix’s template caching. Nathan Long has a great post on how Phoenix uses IOdata to make templates so fast, so perhaps I can take advantage of a similar approach. Thanks for suggesting and explaining that @bobbypriambodo.
As this is a one-person side project where I’m often adding JSON endpoints and corresponding React components at the same time, separate repos with 3 probably isn’t worth the additional complexity, though I agree, @sotojuan, that that would be the ideal, cleanest solution.
Thanks for the helpful responses!
2 Likes
There really is not much overhead there.
3 Likes
I support the idea of a separate repo and then just tossing your bundles in an S3 bucket. If you are using react but don’t want webpack headaches then create-react-app is the fastest way i’m aware of to get started. I did read the previous responses, so i’m aware of your benchmarking goals. Going with option one seems reasonable. I hope you find a setup that suites you best.
2 Likes