kccarter
Can you minimize Javascript inside a heex template?
I’m experimenting with different ways to incorporate a bit of Javascript into some of my pages. (Not using LiveView.)
Consider the following heex template:
<div>
<button>MyButton</button>
</div>
<script>
// Some Javascript goes in here....
</script>
Is there anywhere in the “build process” that I could minimize the Javascript that is within the script tags?
We’re aware we can put code in app.js, and even import other files into app.js, but we’re just curious if there’s a way to inline it like we have. For some pages, we’re only sprinkling a very small amount of Javascript and would rather keep that Javascript code as close to where it’s being used.
Discussions headed down the path of whether the script tag could be a functional component that, at compile time, could take the string and “call out” to something like esbuild for minification, though we have no idea if that’s possible within the Elixir build steps.
The goal here is to see if there’s any merrit in a design pattern that is mostly heex, but with a bit of JS “inlined” in the heex templates, rather than having to fallback to using Javascript files and imports / included.
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #hex
- #performance










First 10 of 11 Posts
sodapopcan
I personally can’t think of any sane way to do this.
You can use esbuild to minify like so:
You would have to use
System.shellto execute this and do the proper escaping and be very careful as that function is prone to injections.However you can’t use
render_slotoutside of of~H. I believe you can do this in Surface since it supports macro components (hopefully HEEx gets them one day as I would love a<.markdown />component). But I don’t think there is any sane way to do this in HEEx.I take no issue with your colocated script tag experiment but I do have to be “that guy” and ask: why do you care about minification if you are only sprinkling in a little bit of JS here and there? I can’t imagine it making a meaningful difference. Minification gets the big wins when the majority of your app is written in client-side JS along with its
pit of dispairnode_modulesdirectory.kccarter
Yeah, I knew that would brought up…
You’re right that it’s likely to be irrelevant with regards to size. More of an “obfuscation” type of thing to prevent internal comments from potentially leaking out into public code.
regex.sh
Hmm, it should be possible.
Write a task that can be run like “mix test” or “mix ecto.setup”
That task will scan all files for some custom pattern (you can put some text in a script tag like x-inline-minify) and will take that code, minify it, and replace it.
kccarter
What if we slightly relaxed our requirement of it being entirely inline and instead did something like a “Javascript sidecar” file.
Template:
Sidecar:
And then have some custom variant of
embed_templatesthat looks for the JS sidecar files and creates functional components out of them?And yes, this is getting a bit into the weeds, so consider this more a discussion of what’s possible and not necessarily what’s best-practice.
sodapopcan
And I knew that you knew that I knew that you knew that I… wait what?
Hey, that’s a good reason!
I’m too tired to suggest any of the truly awful ideas I have around this
@regex.sh’s suggestion isn’t bad, though. It sounds more and more like you may just want Surface. It already has collocated JS hooks.
kccarter
Inspired by this blog post showing how to compile Markdown formatted blog posts into a Module, we came up with the following for minifying Javascript. Curious if there are obvious ways we could improve this as we’re not Elixir experts.
Minification is done by the Terser library and installed as a node module inside our
assetsfolder.Our HTML Module:
A HEEX template:
Embedding JS with the
scripttag directly in HEEX template was problematic. Basic code formatting wasn’t working properly, for example. Using a JS “sidecar” file could be an acceptable trade-off.Questions:
embed_templates?@inline_jsin anyway?Naturally, we might want to embed local Javascript files from other Modules.
ibarch
Since you’ve started writing JS in a separate file anyways, have you considered wrapping your heex template into a custom element? You’ll get not only minification, but caching for free (well, at the cost of an extra initial HTTP request).
kccarter
Not entirely sure I follow you. Our rendered HTML is standard heex templates that may include various function components.
Our primary desire for JS integration is to either “progressively enhance” some pages, or to write very lightweight “reactive” components.
kccarter
For anyone coming across this in the future, we had fun building a working prototype that came close to achieving our original idea with the caveat that the JavaScript was in a sidecar file.
But in the end, it became obvious that the obscurity of such an implementation just wasn’t worth it.
Our JavaScript is now where it should be and our heex templates now just invoke a single line of inline JavaScript to pass a DOM element to an “enhancing” function, somewhat akin to how JS frameworks render a root component into a given element.
ibarch
Here’s an example to illustrate what I was suggesting in my previous comment.
Create a heex component wrapped into a custom element
<my-button>:Define this element somewhere in
assets/scripts/custom_elements/my_button.js:Load this script in
layouts/root.html.heex:If you want to make your components truly isolated Declarative Shadow DOM is now widely supported.