Thoughts and feeling about mixing Elm with Phoenix?

Hi all,

I’ve seen a number of related threads in the past, but I’d still be very curious to hear an up-to-date opinion on this topic.

I’m new to web development, I started off with learning backend frameworks and of the ones I tried I decided to go with Phoenix. I spent the last week or so reviewing frontend frameworks at a high level and I thought that Elm was a particularly interesting one. However, I feel that pretty much all major SPA frameworks are complex and on top of that if you do decide to use it with a Phoenix backend, then you are not going to be making the most of Phoenix (e.g. LiveView and even EEX).

Do you think that Elm and Phoenix are a good combo? More specifically, do you think the benefits that you gain from using Elm justify giving up Phoenix’s frontend features?

Lastly, I’d like to add that the same question can be raised about any other FE framework, so if you have any opinions about frameworks other than Elm, then I’d be keen to hear from you too.

Thanks :slight_smile:

3 Likes

Last time I checked Elm does not allow call out to javascript functions. Most people will have to use some third party javascript code one way or the other, so that’s a big no-no for me.

If you are doing solo project and are happy with with pure elm in the frontend, then there is nothing in phoenix to stop you.

I’m having a great experience mixing Fable (F# to js) with Phoenix.
Fable has Elmish which is Elm architecture on F#.
It uses react as its renderer and using Feliz which is a nice DSL over React, you can turn your individual MVU into a react component.
You can also call into js functions and vice versa and it is simple to write bindings to js libraries if it doesnt already exist.

In fact, I implemented an app in Liveview and then things got so hairy that I rewrote it with just Phoenix and Fable. Alpine js wasnt enough for my needs.

1 Like

Elm dropped Websocket package a longggg time ago and haven’t added it back yet. So you have to use Port™ for that. When it comes to SPA, people use Phoenix Channel with them, the frontend stuff.

I’d say go for it, inevitably write JSON Encoder/Decoder and see if you like it, it’s not very hard but cumbersome for many people. Elm also lacks of libraries, if your app UI is not trivial, you have to write your own. You can wrap JS lib within HTML Custom Element and use as a regular node in Elm, as long as the libs do not mutate DOM and confuses Elm runtime (and crashed)

–advance–
You may not encounter this downside of Elm VirtualDom, but Html.Lazy is almost impossible to optimize at non-root level (short explanation is; Elm lost object references almost all the time, ref equality check easily return false)


I’d say list a couple UI/UX features you want to implement and re-evaluate frontend stuff again. VirtualDOM is already an unnecessary for declarative UI development, try evaluate Svelte, the simplest “language & framework”.

-advance-
Try Solidjs or start small with https://github.com/WebReflection/uhtml/blob/master/DOCUMENTATION.md (JS Template Literal based with some event/attrs binding)

Again, what you are going to implement is important.

list a couple UI/UX features you want to implement and re-evaluate

3 Likes

Elm is a great frontend framework and it works splendidly with Phoenix as an API layer.

I feel that most comments about lacking websocket support or the fear of ports are largely FUD, since ports are a great (i. e. streamlined and safe) way to do interop. The thing you need to account for is: you cannot do synchronous calls to a JS library through ports.

Elm is in my opinion also a good match for Elixir since it also defaults on immutability and functional concepts while programming (e. g. it uses map and reduce for iterating through lists). It also has great documentation for most things.

But Elm (as well as React and nearly all other FE frameworks) manages its own application state and you absolutely should have a solid usecase that justifies introducing this complexity. The main reason one uses these frameworks is to provide a user experience where interactions feel instantanious. My feeling is that this is, in most cases, not enough to justify introducing what is essentially distributed computing.

So I tend to use the following algorithm:

  1. Is this a project with an existing stack? If so: use whatever is there!
  2. For green field projects: use standard Phoenix unless
  3. I need interactivity (form validation, notifications, …): use LiveView unless
  4. I need local state (e. g. for games): use Elm/React/Vue/… components rendered as part of the Phoenix template unless
  5. I need true offline support: use Elm (I typically cannot afford runtime errors in these scenarios)

This is interesting! Would you care to elaborate what the features were you could not implement, or felt were not a good fit for LiveView?

5 Likes

Thanks for sharing! I’ve never heard of Fable before, but it does look promising. I have to admit, I was genuinely thinking that Phoenix + LiveView + Alpine would be more than enough, so it’s particularly interesting to know that it feels limiting to some users.

Thank you for your response, it does make a lot of sense. Your approach to stack selection is also very useful for beginners like me, so thanks for sharing. I completely agree that SPA frameworks bring a noticeable layer of complexity with them, however it also seems that there is a gap where an SPA might be an overkill while LiveView + Alpine (or some other small JS framework) is not quite enough.

Even though I mentioned that Elm really appealed to me, would you say that a more mature and traditional FE framework is a better (or at least easier) choice in most circumstances?

Also, can you recommend any resources for getting started with Elm 0.19.1 and Phoenix? It appears that most available tutorials on this are no longer compatible with the latest Elm version. One potentially good resource that I’ve found is the elm-phoenix-websocket package here.

Thanks!

This is covered by point 4) in the list. What I tend to do is to render a component inside a normal Phoenix template (e. g. <div id="componentRoot"></div>) where I then render a JavaScript application that can also call API endpoints or react to websocket messages if it must.

But I keep the navigational logic in Elixir and Phoenix. That way I can leverage established standards for authentication and authorization - and this is a huge win. (But this is a pet peeve of mine, so please take it with a grain of salt :smiley:)

But I assume that you have something specific in mind. Could you extend on that?

No. Elm is in my opinion the best choice for frontend/SPA development by a long shot. That is not to say it is perfect. In fact far from it. But is still the best option for beginners and seasoned programmers. In fact that says a lot more about the competition then about Elm, but I stand by that.

I have (professionally) developed and / or supervised projects in Angular (1/2/…), React(Native), Ember, Vue, Hyperapp, Elm, jQuery(-UI) and Reagent (ClojureScript) and with the exception of Reagent and Elm all of those suffer from long term […] rot in my experience.

(I just deleted five paragraphs… ranting is not too productive :smiley:)

There are three cases where I’d advise against using Elm (after having decided that you need a frontend framework):

  1. When you need to be able to show off proficiency in JavaScript or a specific framework.
  2. When you hate beeing bossed around by your tools (or doing things thoroughly)
  3. When you need to use specific, ready made things that do not integrate with Elm. In which case point 1) from my algorithm takes effect.

Acutually I cannot. There are so few resources because there is not much to it. You can use the package you’ve found which looks quite good but actually there is no magic in it:

  • Using a Phoenix REST/GraphQL-API is simply using those APIs
  • Using sockets is not more than using the standard Phoenix socket client, setting up an Elm port and sending messages over this port whenever they arrive

That’s it.


That beeing said: this is my experience with all these technologies. In the end whatever you choose needs to be what you’re comfortable with.

(Reflecting a bit: ClojureScript with shadow-cljs might be a worthy contender to Elm in certain situations, but oh boy is that not beginner friendly :joy:)

4 Likes

Awesome, thanks for such a thorough write up!

No, to be honest, I do not. I’m just getting into web development and I have a couple of project ideas in mind, but before I get to them I would like to get my head around the available tools. In my opinion, Phoenix covers a lot of use cases, but there may still be a need for a frontend framework (e.g. if you want to go serverless). You could say that I spend a little too much time on this background research, but if I didn’t, then I wouldn’t have either Phoenix or Elm. I’m not rushing anywhere :slight_smile:

2 Likes

For a pure static frontend application using jamstack, can I develop in elm, push to github and have auto-deployment on vercel/netlify/render? I was under the impression that those platform services are centered around the javascript eco system; anything outside npm/yarn is only supported poorly if at all.

I’ve used Elm and Phoenix Channels together before websocket support was dropped, which worked great!

When websocket support was dropped however, a lot of boilerplate was suddenly required to regain a semblance of the original functionality. It required a lot of changes and was significantly harder to read/maintain since you cannot use Ports in the same way as the normal builtin Elm functions and datatypes.

Another problem I had, wanting to use Elm with a remote HTTP API, is that it is impossible to string together multiple port-calls. You’ll end up with a lot of boilerplate for this as well. I ended up contributing to a library called Porter to make this slightly more bearable, but its usage is not 100% idiomatic because Elm prevents you from doing so.

The fact that you cannot publish Elm libraries with JavaScript code in there (and so have to rely on unstandardized 3rd party package management solutions for these) makes this worse.


I like the ideas behind Elm. I think it is a very cool concept. I very much like what is contained in the standard library.

There are however many situations in which I would not recommend people to use Elm right now. Multiple features that I deem important in a general-purpose web-targeting programming language are still missing. It is pre-1.0 software, and Evan Czaplicki has said from the beginning that he prefers a ‘super good’ language in the long run rather than an ‘okay’ language right now.
This is probably a good decision for the language in the long term. It does mean that in the short term it is less suitable for complex/important projects.

2 Likes

Interesting, thanks for sharing your experience.

Do you still use Elm whenever you need an SPA or did you switch to another solution? Do you see it as an option to use Elm 0.19 and not upgrade to 0.19.1+? Lastly, as long as you are not relying on websockets, the entire experience should still be alright even with the newer versions, right?

Just my personal opinion here, but it sounds like a risky approach as a lot of people might simply abandon a language that mainly cares about becoming “super good” in 10 years or so.

I am using Phoenix LiveView for my current projects.
If I encounter another situation in which I really need a full-fledged SPA solution in which e.g. disconnects should not stop the SPA from running, then I’ll probably reach for PureScript.

No, I do not see it as an option to stick with 0.18 and not upgrade to 0.19.x because you’re stuck working on a deprecated and unmaintained system.

There are other tradeoffs in using Elm (some objective, some subjective), but since this topic is about ‘mixing Elm and Phoenix’ I did not intend to go into more detail there. If you want to read more, I suggest the article Elm is Wrong combined with Evan Czaplicki’s response to it, to form your own opinion :slight_smile: .

2 Likes

I hope I can add some “beginner view” to the picture: I have used / am using Phoenix + Elm for two personal (toy?) projects.

These are my first actual “works” in both - started this year -, although I followed Elixir and Elm for a long time - but only reading and thinking is of course way different to working with. I do quite a bit of web programming with C# and Angular for a living and that obviously influences my opinion.

I use Phoenix solely for the API and I think I would agree with you that not using templates and Liveview feels like I’m missing a big part of what makes Phoenix great. But considering I’ve never actually used those I could totally be wrong! Considering this is an Elixir forum I will just say: it’s a blast to work with!

About Elm: I really enjoy it. It’s a great language from my perspective and hasn’t “let me down”, so to say. I do get that I might have been lucky because my requirements aren’t high though…! I do think that the non-native websocket support is not an issue though. I am using that in my second project now and it’s really fairly simple! Maybe about 20 lines of JS “plugging” Elm and the Phoenix JS Client together.

The thing about my usage of Elm is, that I wanted to use it. I think it’s very often smarter to prefer LiveView if you can get away with not using a front-end framework. It’s just so much simpler sometimes, if your website doesn’t need the extra something?

My conclusion: I am using it and would again, because I think it’s fun and productive. I have no steakholders nor hard requirements though, which makes life “easy”. Also in these projects I’m the whole team and have no timeboxing.

Elm makes me feel like I’m forced to work well. Elixir is as great and lovely as we all know. For learning purposes or school / university projects I would recommend highly.

2 Likes

Awesome, thanks for pitching in! Your situation sounds very similar to mine, except I don’t do web development professionally. Like you said, I realise that you can probably go a long way with Phoenix alone, however, when I decided to get into web development, I wanted to familiarise myself with a toolkit that would cover all possible scenarios and there is certainly still a niche for SPA frameworks. I thought that Vue and React are solid, however I’m not really a fan of JS, for that reason Elm really appealed to me. You feedback certainly gives me the encouragement to give it a proper go. Thanks again!

2 Likes

Not only JS, you can use HUGO (Go) and elm-pages (Elm) which I am pretty sure is supported as well, not to mention Jekyll (Ruby)

I know hugo and jekyll can be used in vercel; Not sure about elm. At least it is not listed in the documentation:

Not sure by default but it does not seem so hard to deploy with Netlify. Here is a starter project with Deploy to Netlify support

Thanks. Didn’t know you can install elm by npm install elm.

With Elm -
My primary reason to choose Elm is

  1. The MVU pattern or Elm architecture or TEA for short.
  2. Type safety and the excellent compiler. I want to be able to come back to project after 6 months and refactor with confidence.
  3. I want zero runtime exceptions happening in places I dont have a watch over.

Sooner or later requirements happen where I have to reach into JS via ports. I actually don’t mind doing that. I wrote an entire application with the view logic on Elm and the backend communication via phoenix channels and Elm ports.

But Fable offered everything that Elm did and more… better integration with JS. MVU with the ability to convert a small MVU component into a react component that could then be reused. (This is also possible with Elm but Fable is low ceremony). Ecosystem with wrappers around popular UI frameworks like material. etc… Integration with Google Maps sdk for example is much easier to do with Fable than with Elm.

Liveview -

I was trying to say Fable-Feliz might be a better alternative to Elm if Phoenix is the backend. If Liveview meets the requirements without the need for a FE framework then there is no need for Elm.

I’m excited about Liveview and use it where I can. Where I cant, I know the problem might be ‘me’ and not Liveview…
When I want to move things around and experiment fast and refactor with confidence…

  1. The Liveview setup, my requirements etc… was pushing me to use server roundtrips for UI concerns. Alpine is good but has limitations and clients are used to the UX and interactivity offered by an SPA. Over time and refactors later, the sprinkling of JS on top tends to grow into a thick layer (tech debt). This is not a problem if one has the pleasure of spending time and effort on it in the future.

  2. UI state has a tendency to mix with business logic state. This is not a problem if one is disciplint and promise not to cut corners and all the people who work on the code adhere to the oath. This problem is a bit easier to handle in MVU.

  3. Components become shape shifters with changing requirements. This could get pretty hairy when requirements change rapidly and you want to iterate before getting your component designs right. i.e should a component own its state or should the parent.

  4. Some requirements makes me drop to down to pubsub to communicate between components. After a while I no longer know who is talking to who and who is the observer and who is the observed. (This is where TEA shines, unidirectional control flow).
    I value the ability to come back after a year and grok the logic in a small component without having to worry about all the actors that maybe associated with that component. and sequencing of events etc…

  5. At this point, I would like to chuck data into an available data-table js component than wire up live view with table search, column sort, prefetch etc… and focus on business logic. (I am watching the surface library with interest)

Some of these are teething troubles and most rise out of me being too dumb to work without a strict compiler to catch my errors.

I’d say it is a matter of personal taste, long term maintainability and individual use case / business requirement.