A Balanced Guide to Whether to Consider Elm for your Project

Danabrams
4 min readApr 12, 2020

--

There was a recent article entitled something like Why I’m leaving Elm that has stirred up a lot of controversy. I’m concerned that a large number of readers lacking context are drawing hyperbolic claims from that article and I wanted to try to correct them and offer a more balanced guide.

I’m an experienced Elm developer with several years of professional experience in the language and a reasonably frequent speaker at Elm conferences, as well as a co-organizer of one. I’ve written complex applications in Elm and pushed it to it’s limits, including it’s FFI’s, which the usual most-contentious part of the language.

I love Elm, but it does have a few against the grain design-decisions that are a contributor to this kind of article showing up on the front page of Hacker News or Reddit once or twice a year. Those same design decisions lead to some of the beautiful magic of the language.

First, why you might want to use Elm:
1) No runtime errors, if using pure Elm. I don’t want to say this is a 100% guarantee, but it’s close to it, perhaps 99.98%.

2) It compiles small and it’s fast, among the fastest Web frameworks there is, more in line with super-fast Svelte than still-pretty-fast React.

3) Well-designed APIs. Elm is both a language and a framework, and the community puts emphasis on great API design.

4) Speaking of community, the community is generally terrific, helpful, and incredibly beginner friendly.

5) A purely declarative way of writing html.

Serious Reasons you might not want to use Elm

  1. You’re writing a server. Elm is a frontend language that compiles to javascript. There’s a commercial product being explored by experienced Elm-developers who are not on the core team to write a full-stack framework, but it’s in closed Alpha, and when people say they’re writing Elm, they mean front-end, browser applications.
  2. You need something like React Native. Elm doesn’t have this yet. There was a very interesting Google Summer of Code Project a few years ago by a very talented young developer, but this was just a proof of concept. Browser only for now.
  3. You want to leverage a large number of JS ecosystem packages, particularly those that manipulate or generate DOM nodes. JS-Elm interop is the most controversial aspect of Elm, and the rest of this article will be devoted to that.

OK, I think it’s a good choice, but what about JS-interop. I’ve heard there is none.

There is JS-interop, but it works differently than most other languages that compile to Javascript. Indeed, it’s make the exactly opposite choice of Clojure/Clojurescript. Elm believes its Javascript runtime IS an implementation detail, not core to its existence.

Because of this, the language supports two main ways to interact with Javascript. Ports and Whitelisted Packages. Additionally, if your business requirements allow you to use Web Components, Elm will treat them just like any other DOM nodes.

I’m not going to rehash what they are or the pros and cons of each, but give you some key ways to evaluate whether Elm’s interop will work for you.

Will Elm’s JS-Interop be enough for me?
In 90% of cases, yes, but at the margins, you may find some things that are either impossible or much harder than if using another language or framework.

  1. I need to interact with a JS Library or web api that doesn’t have a wrapper, but doesn’t really interact with or create DOM nodes, like Socket.io or local storage. Ports are really great for this, you’ll shouldn’t let this discourage you from Elm. It’d be great if we could figure out how to make them asynchronously bi-directional, but it can be worked around.
  2. I need to interact with an unwrapped JS Library or web api that interacts with or creates Custom DOM nodes, like D3.js or hls.js. Can you wrap it in a Web Component? This will be easier than it would be to develop a kernel module anyway. I’ve done this successfully with hls.js.
  3. I absolutely need to use a library or API that grabs a DOM node by id and manipulates or interacts with it. If you’re just changing props or attributes, there’s a greater than 98% chance you’ll be fine, but there are edge cases I’ve found where you may be out of luck. If what you’re doing is calling functions on the node, such as play() on the media API, I think you probably shouldn’t do this. It may interact with the Elm Virtual DOM in unexpected ways. Perhaps build that one component as a web component or consider a different language or framework, so long as the interface can work in a purely declarative way.
  4. I have to interact with a standard DOM node that maintains its own state and manipulates it via functions, not props or attributes. This is really an extension of #3. This is a really annoying case, for me especially, because I work with video elements and they’re a prime offender of this. You can always make absolutely sure you give the element a unique id, use document.getElementById() and call the functions via a port, but you or someone on your team at some point will copy and paste without an id or a duplicative id, trust me. I generally think manipulating the dom nodes created by virtual dom from ports is not a good idea, that’s my hard won experience. In this case, you want to write that portion of the app as a web component, or you may be out of luck.

The cases above shouldn’t discourage you for most projects. For the edge cases above, you may want to use something else. If you can use Elm, though, I think you’ll fall in love with it. My recommendation is spend time thinking about how to design your internal APIs and types, and you will have a good time.

--

--