<script> tag at the bottom of the template with some common functions in a global object created in
Is this a reasonable pattern? What are recommended/best-practices around this?
Sorry if this question is a bit naive, I’m pretty new to web-dev and js in general.
Welcome to the forum!
If you don’t want to use a bundler you can always specify:
mix phx.new PATH --no-webpack
Any additional assets are then kept directly under
It may be necessary to adjust the endpoint to pick up assets under non-standard directories.
That being said
Hi, you can create helper functions into separate files, it’s a very common and modular approach, something like:
helpers/buttons.js - Handle clicks for buttons
helpers/inputs.js - Handle events for inputs
helpers/animations.js - Handle animations for elements
Then you just import those files inside your main script to include them in your bundle.
Also I’d recommend using the
defer attribute rather than putting
<script> at the bottom. With
defer the browser will download the script while the HTML is being parsed. If you put
<script> at the bottom, the browser will parse the HTML and when it hits the
<script> tag, it will download the script, so technically is slower.
I’d definitively not recommend
async if you split your bundle.
defer seems to be well supported these days.
The problem with a plain or
head script is that it delays FCP (first contentful paint).
You still have to be careful in some situations:
Use async or defer
Take a look at Stimulus. This is exactly its use case.
I think this is a pretty reasonable way to start for your use case. The only possible issue is that your JS doesn’t go through the webpack pipeline if you do it page by page so any transformation / optimisation / minification will have to be done manually.
There is also the option of adding more entrypoints to the webpack config file. I tend to do this when I have shared JS relating to a feature spanning multiple pages. So instead of just app.js or sprinkles at the bottom of the page I’ll have blog.js, store.js, admin.js e.t.c.
Thanks for taking the time to reply!
I think I understand webpack a little better now, but what I’m a little unclear about is why we need to use a bundler at all with phoenix apps.
If my understanding is correct, SPA apps send a big blob of JS to the client, which once parsed and initialized creates markup, and handles everything client-side. So, it makes sense for them to pack everything into a single
app.js and send when the page first loads.
In phoenix though, everything is handled on the server, so I’m confused as to why we’re sending the whole
app.js bundle on each page load. It’s not like we send all our HTML each page load, we only send the layout and what’s required for that page to render, why not do the same with JS? Load common libraries in the
layout template and load page specific js in their respective templates.
I feel like I’m missing something obvious, but not sure what it is.
You are not “sending”, you only specify the resources source. The browser then chooses to cache or not to cache this resource and is free to not download it again in the future.
This way you can massively decrease the number of requests made to your server. Also a single large request is usually more effecient regarding the payload/header ratio than many small ones.
Of course you are totally free to use many entry points and separate your scripts that way you describe.
The bundler organizes the code in such a way that the various modules only interact with one another in a well defined manner. Browserify started doing this in 2011. It’s only since about 2017 that browsers started supporting ECMAScript modules natively - and even then using them tends to lead to a lot of additional requests because the aren’t bundled.
Thanks! It makes sense now, I was naively assuming browsers download it everytime.
Hi everyone, newcomer here
Is there any pattern or library that has a similar pattern to Laravel’s blade templating ?
I think it is very straightforward when we want to add css or js on a single page.
@section('title', 'Page Title')
var foo = "bar";
I’m not aware of any library doing this like in Laravel, but it’s easy enough to set it up on your own.
Take a look at
You would have a bunch of these in your
app.html, or wherever you define your top-level layout files:
<%= render_existing @view_module, "page_layout/head_scripts_css.html", assigns %>
<%= render_existing @view_module, "page_layout/head_scripts_js.html", assigns %>
and then a
page_layout folder structure per view template where you would create and place these
head_scripts_css.html as needed.
The big difference between
render_existing and what most templating engines allow for is in the possibilities in nesting.
In phoenix you can only use
render_existing for view modules you know about. So e.g. the outer layout html is aware of the view_module the controller told it to render (might be selected explicit or implicit). It’s however not aware of arbitrary nested partial templates, which are used somewhere deeper down the call stack of templates rendered within other templates.
render_existing doesn’t play well when you want a partial to add something to the layout.