anon9372508
Looking for input about how to better approch JS development in Phoenix (not just liveview)
First Hello.
Secondly:
I want declare my intent before I say anything else so that I’m not misunderstood.
I want to have a conversation that can typically become very contentious.
I don’t wish to be contentious, disrespectful or contrary for the sake of it.
That is not my intent.
I love the free work that other people have created for me that I have not ever had to pay for.
I’m not saying any of the following to be disrespectful of their hard work. So with that thanks for everything.
What is my intent?
My intent is to address my core concerns and to get input about how I can already use existing solutions or possibly develop a new solution to address these core concerns.
I think by addressing these concerns we can make phoenix better for everyone and possibly attract other typically front end heavy developers to adopt phoenix.
What I wish I had in Phoenix.
Following after this are my core concerns and wants as I think they best describe the flow.
In general I want to use phoenix as my primary framework and find a better way to make more expressive js applications in it. I love liveview and fully understand it, there are just these tradeoffs I keep finding myself wishing I didn’t have to make and I wonder if there is a better middle ground where we don’t have to make these compromises. I realize that some of my asks may never happen, I still think they are worth sharing so that 1: You considered the idea, 2: we have meaningful conversation that maybe brings to life new ideas.
So with that lets begin.
The HTTP REQUEST:
1A:
I want to use Phoenix as a primary router for my initial request and provide SSR for SEO.
I think the phoenix router / plug already does a good enough job of this and see this as the right way to address that concern.
Also I think Phoenix controllers do good enough for this for the great majority of projects.
1B:
I want all sequential requests to not require a full page load. (IE hydrate then hand off)
I am aware that live sessions and patch requests via liveview can address this.
I am aware that liveview does a dom diff via the socket so no need to call that out.
I do want to come back to this later as I feel liveview is coupled to the socket which I kind of see as the primary barrier to working with other frameworks like svelte or astro.
I feel the compromise of prefetching like other frameworks do would not compromise on performance significantly and possibly would make it much more easier to integrate these other framework with phoenix for SSR. I would love to see something like sveltekit:prefetch or @astrojs/prefetch for all sequential requests personally
1C:
I am aware that liveview mount callback can also addresses the initial request for SSR/SEO 1A
The Template And Code Organization
2A:
I want to use HEEX templates for general HTML and componentizing blocks of markup.
I know functional components already do a good enough job for this.
2B:
I would like to have scoped JS like that of other front end frameworks built in to the heex template
Likewise I would like to have scoped CSS like that of many of the frontend frameworks built in to the heex template.
2C:
I know JS hooks solves alot of these issues, but they really don’t feel well organized in my projects and leave me feeling like they are a compromise and not a solution. I tend to wish they had better proximity to the code elements they relate to rather than just living in my assets/js folder.
Also having to use hooks as the primary way of code splitting for your JS is not great, though it does work.
I believe I seen something possibly in the works for better organizing hooks so I guess there is some solutions for that. Though at the end of the day they are still just hooks. It would be nice to have a way outside of live view specifically and something more integrated as a part of heex in general when dealing with JS. Given heex is about embedding elixir in html and the fact html is so closely tied into CSS and JS it seems integrating support specifically in heex more sense IMO.
2D:
Same goes for Phoenix.LiveView.JS.
Its just not as pleasant of an experience developing UI interactions with LV.JS as it is working in say Svelte, Vue, ect components. I tend to feel less confident about working in this area of my codebase when working with LV. This is one of the major reasons I wish for scoped js in the heex templates as to keep the related code closer to the areas they relate to. I don’t know how I feel about just throwing in a script tag into these templates either.
The Event Lifecycle and the Socket.
3A:
It would look as if the great majority of compromises made are the result of the web socket.
I would ask:
- Is the performance gained really worth it?
- Can we have relative performance but open up more possibilities by doing it differently?
3B:
We still have Channels for when we really need that pubsub via sockets.
3C:
Server Sent Events are also a possibility.
3D:
https://hologram.page/ I think shows some of these trade offs in terms of the websocket and requiring network for things that maybe should stay client side till they need pushed to the server. Consider Offline mode and how the socket has been a barrier for that.
3E:
Page transitions and other more rich interactivity via js feels impossible with liveview. Again I feel this is the tradeoff as a result of the socket.
3F:
Change tracking in LV and Client side only state is a real battle. It tends to make me think maybe this does not need to be statefull on server after all. But then I realize the pain of duplicating models on the client to replicate that of the models on the server. There has to be a better way even if the sever is the source of truth. Let alone the compromise of offline mode or service workers, push events ect.
My conclusions so far:
- I love phoenix, and want to keep using it as my main application.
- I like the general idea of liveview but feel at odds with it when I compared to other js solutions.
- I wish I had a more unified development experience (mono repo) when working with other JS frameworks inside of Phoenix. I realize this was how we got to liveview.
- The socket requires a lot of tradeoffs even when using channels.
- I’m not sure the trade offs are worth it for the socket given there are other like solutions.
How did I get to this place?
I’ve spent some time trying to figure out how to get the best of both worlds.
- Phoenix + Vue,
- Phoenix + Svelte (including live svelte)
- Phoenix + liveview + other js frameworks
I recently deiced to give mix phx.new --no-assets --no-live a try and see what its like to just divorce from liveview as much as I could and write vanilla ES modules + channels and once trying server sent events.
it was not a horrible experience but it did highlight what I got out of the box for free.
In someways it inspired me to want more freedoms at the cost of out of the box features.
For example I’m not sure I will be going back to daisy UI or even tailwind moving forward.
Any ways I don’t mean this to be a rant about liveview,
I find myself constantly thinking about these problems and find myself even telling myself that I should just develop a whole new solution.
I would love to see what other people say about what I have said here.
Thanks for reading this.
Most Liked
Jskalc
Hello
I wanted to add my 2 cents here, as I had similar “problems” with LiveView and currently I’m quite satisfied with my workflow. For context, I’m the creator of LiveVue library, and I have quite a deep familiarity and preference for Vue frontend framework. I gave a talk “Why mixing LiveView and a frontend framework is a great idea” during ElixirConfEU 2025, recording is not yet out but you can check slides here (desktop-optimized)
So, in short:
- I love declarative approach of LiveView, and having a stateful connection to the server which allows to skip writing API endpoints
- I don’t like JS interop - JS module is limiting and imperative, hooks are detached and imperative as well.
- LiveComponents are nice but have awkward API for updates, and can’t handle handle_info etc. Also doesn’t solve client side state.
What I want:
- Be able to decide where to keep state - on server, or on client?
- Have declarative rendering on both sides
- Use amazing features of LiveView without problems
My current approach:
- Use LiveVue in the same way as Interia.js does - one top-level Vue component per LiveView
- Ditch HEEX, render whole HTML in Vue.
- LiveView is responsible for updating props which are transparently propagated to the frontend.
- Vue can decide if given user action should be handled locally or propagated to the server
- I’m colocating Elixir files and Vue files.
- live-navigate is fast, since it only updates props of a Vue component. Update is synchronous, no flash of unstyled content.
- SSR is available and quite fast.
- Using Vite instead of ESbuild (amazing DX)
Using that approach is not yet as straightforward as I’d like, I’m improving library to make it so (eg colocating requires moving node_modules to root etc). Igniter installer is also coming. Not sure if it checks all your boxes, but wanted to highlight there’s a possibility to do something like this without using Inertia ![]()
Some screenshots from my current project.
bartblast
Hologram is fundamentally different from LiveView. While LiveView sends diffs over the wire, Hologram transpiles your Elixir code to JavaScript for client-side state and instant DOM updates.
You’re technically right that JS is abstracted away, but the development experience differs - there’s no abstraction leakage to deal with due to transpilation.
Worth giving it those 15 minutes - there’s a big update coming within the next 2 weeks with several roadmap items completed! ![]()
sodapopcan
Poking my nose in here for this massive thread I’ve been silently following to confirm yes: I value this a LOT. I really dislike the “what if we need an API” argument because:
- What if we don’t?
- If we do, I don’t see having a separate customer-only web API as a bad thing. Provided you have “skinny-controller” design this isn’t a herculean feat and lets you draw a firm line between what is internal v external. Also, these days we have Ash which makes this trivial

Popular in Discussions
Other popular 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
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex












