I’m working on an early draft of an article on strategies for handling JS interop in Elm. While I have several projects of my own to refer to, I think the end result will be more useful if I can also draw on challenges other folks have had connecting Elm to JavaScript.
I’d like to hear about your most difficult interop efforts, particularly if you ended up having to give up or go a different route. Specificity will help, so if you can share specific libraries or UI widgets that were problematic, I’d be grateful! If that doesn’t make sense for your particular story, I would still like to hear about it.
I was integrating Elm with Leaflet.js, so I could visualize thing on a map, and it came with some challenges.
Leaflet is a really nice library, and I’d definitely recommend it to someone if it fits their use case. The challenge is that Leaflet and Elm both want to own the state, so you end up sending a lot of data across ports and maintaining the same data structures on both sides.
Ultimately I ditched Leaflet for the slippy map library that Jonas Coch presented at elm-conf 2017. Leaflet was nice, but the complexity of interop wasn’t worth it to me.
I need to second this. We’ve switched back to react for mapping applications with very heavy data visualization requirements simply to benefit from MapboxGL.
I am really new to both Elm and Javascript so there maybe some concepts that I missed of solutions that I could possibly use.
I was trying to use https://deeplearnjs.org/ as a library for calculation in Javascript(Actually Typescript but similar) in the background and use Elm for UI. A sample calculation code can be found at the bottom of the page here: https://deeplearnjs.org/docs/tutorials/ml_beginners.html. The calculation will take some time and I would like to prioritize UI from Elm and only start calculation after the UI has loaded.
After that I also wanted to make a progress bar-like feature to update to Elm after some rounds of computation.
I tried to use ports, there is no problem about sending information to Elm, but it seems rather troublesome to pass the information from elm back to Javascript without messed up with the calculation logic. Before using Elm, all the logic of the calculation are all in one piece. However by using ports.*.subscribe, I need to wrap all the actions in different steps after Elm rendered in different functions which mixed with UI logic and very hard to grasp what calculation is going on.
@cwhy
That sounds as if your ports interface is too scattered. Do you know of this talk that advises having just two ports in Elm - incoming and outgoing - and use JS to figure out what to do? https://www.youtube.com/watch?v=P3pL85n9_5s Cheers!
I used ports to talk to firebase using the native JS firebase api.
The experience posed no significant problems, and forced me to cleanly isolate my database layer. A benefit was that porting from Firebase to Cloud Firestore took less than a day for a rough version.
It’s modelled so that all data state comes from Firebase, and data state isn’t updated internally. Instead, change operations are sent over a port to JS and if successful, a change in data will trigger a send back into Elm.
How big is your data state? I worry in schemes like this about repeatedly decoding large — as in structures with 10’s or 100’s of thousands of elements — on each data store update.
A user can have several “projects”. When a project changes, it happens on the JS side, and the entire thing is serialized and sent to Elm over a port.
I’m currently tracking about 10 projects, the largest is currently 44K of JSON (hundreds of objects, a thousand pretty-printed lines). The app is snappy even on mobile.
I only started this project after the talk you mentioned and based my code on that. The problem is that my ports are not scattered (As I only have two ports) but my calculation is.
With the caveat that I don’t have a lot of detailed insight into your project, my suggestion would be to put all of the calculation logic into JS, and just let the Javascript side completely own the state of the calculation. As the calculation progresses, I would have it send messages to the Elm portion of the app to inform it of the current state of the calculation to update the display. Hopefully that’s not too unhelpful or naive of suggestion due to my lack of context.
I think this is likely to be a common theme of what I end up writing on interop. When there’s state involved (such as progress & intermediate calculation steps), it’s important to have a clear idea of which side of the ports is the system of record for that state. The side that doesn’t own the state requests actions (like starting/pausing a calculation) that may alter the state, but relies on the owner of the state to push updates back when changes happen.
A theme that argues essentially for more logic in JavaScript (and hence less in Elm) should probably prompt an examination of other mixed language environments and projects.
From what I’ve seen over the years, the boundary that comes with multiple languages always comes with expenses around plumbing and cross-language debugging. This puts pressure on the minority language to be really good at what it does in order to justify the cost relative to the majority language. Usually, that “really good” manifests as a desire to write more code in the minority language to the point where the balance tilts: “This is just the scripting language that we use to wire together the real features, put up the UX,…” becomes “Hey, it turns out most of what we do can be thought of wiring things up and this scripting language is great.” Having bet on a non-standard technology, people tend to want to see that bet pay off in a big way.
Narrowing the scope of what one uses Elm for may well improve interoperability with JavaScript but if it leads to projects investing more effort in hiring people to focus on JavaScript code, those people may start pointing out that JavaScript has a long history of handling the tasks from Elm’s narrowed domain. I wouldn’t make this a central part of any study of the issue but it seems like the sort of question that should get some consideration in any conclusion.