bartblast

bartblast

Creator of Hologram

Time for Hologram <> JavaScript Interop - What Would You Like to See?

It’s time to implement JavaScript interop for Hologram!

Eventually, there will be Hologram wrappers for most APIs, but sometimes we’ll need escape hatches - especially when working with legacy apps or integrating 3rd party libraries. Things like:

  • Integrating charting libraries (Chart.js, D3, etc.)
  • Using JavaScript-only APIs (Web APIs, browser-specific features)
  • Calling into existing JavaScript codebases
  • Leveraging the vast npm ecosystem

How would you envision a Hologram <> JavaScript interop API/DSL?

Some questions to spark discussion:

  • Should it be declarative or imperative?
  • How should data be marshaled between Elixir and JavaScript?
  • What would the ideal developer experience look like?
  • Are there specific JavaScript libraries you’re eager to use?
  • How should errors be handled across the boundary?

I have some ideas brewing, but I don’t want to bias the discussion by sharing them upfront. I’m genuinely curious about your use cases and what would make the most sense from a developer ergonomics perspective.

Looking forward to hearing your thoughts!

Most Liked

olivermt

olivermt

If I want to use google maps I am not looking to avoid javascript, I want to use javascript in the most practical manner possible.

Hologram is about isomorphic solution to 80-90% of your app, then for the rest where I can use pre-built stuff that is supported by a profitable business I just want a very ergonomic way to do javascript.

I do not think Bart spending time re-implementing Javascript in elixir is a good use of his time for that :person_shrugging:

bartblast

bartblast

Creator of Hologram

I’d prefer to avoid basing architectural decisions on polls though :wink: Not that I don’t like polls, but I’m trying to provoke a deeper discussion here and am more interested in understanding the deeper trade-offs for Hologram’s specific context.

I’m honestly on the fence here and looking for someone to convince me why one of these approaches is genuinely better than the others. I don’t really care if something is familiar - what I care about is the best DX in general. Sure, familiarity might be part of DX, but there are many other factors like ease of use and ease of maintenance.

olivermt

olivermt

For me the usecase is very straight forward and I suggest you even use it both as a thing to prototype with and as a showcase of interop.

I want to do a <div id=”map”/> and then initialize google maps on it.

In regular liveview this would just mean setting phx-update=”ignore” on it and start mapping JS hook events.

In Hologram I have no idea what would be most idiomatic since I haven’t really dug in yet due to lack of said JS interop.

I propose three usecases:

  1. Get the corners of the map (essentially the lon/lat of top left + lower right)
  2. Add a marker (ideally with some props like marker color etc)
  3. Delete a marker (this means you need to thread through back to Hologram the ID of an added marker)
bartblast

bartblast

Creator of Hologram

Let me clarify my current thinking on Hologram’s JS interop direction.

@Eiji - your examples are really helpful and show how high-level Hologram modules for abstracting JS Web APIs could work (like Hologram.DOM.query_selector, Hologram.DOM.add_event_listener, etc.). That’s a compelling proposition and we may very well go that way once simpler primitives are implemented and test themselves in battle.
But for now, I’m focusing on the lower-level foundation - just enabling basic interfacing between the Elixir world and JS world. The goal is simple: allow calling JS code from Hologram and vice versa, something more primitive that those higher-level APIs could be built on top of - something that enables calling Web APIs or interfacing with existing JS code like in the example described by @olivermt.

I’ve been analyzing different approaches to JS interop across languages and frameworks and found three main categories that could apply to Hologram.

1. Messaga passing

The first approach is message passing, like Elm’s ports (as mentioned by @kingdomcoder) or Phoenix LiveView hooks.

In Elm, you define ports for sending data out and subscribing to data coming in:

port sendData : String -> Cmd msg
port receiveData : (String -> msg) -> Sub msg

Then in JavaScript, you connect to these ports:

// Listen to data sent from Elm
app.ports.sendData.subscribe(function(data) {
    console.log("Received from Elm:", data);
});

// Send data to Elm
app.ports.receiveData.send("Hello from JS")

LiveView uses a similar pattern - it communicates with the JS world through hooks.

Pros: Clear boundaries between language worlds, explicit control over data flow
Cons: Communication overhead, forces async patterns even for simple operations

2. Foreign Function Interface (FFI)

The second is Foreign Function Interface (FFI), like Gleam uses. You declare external functions that map to JavaScript:

@external(javascript, "./my_js_file.mjs", "greet")
pub fn greet(name: String) -> String

With corresponding JavaScript:

export function greet(name) {
    return `Hello, ${name}!`;
}

This pattern is actually very common - most bindings with C/C++ libraries use this approach, and even Rust NAPI works similarly where you declare foreign functions that bridge between languages. For Hologram, this could look like declaring JS functions directly in Elixir modules.

Pros: Direct function calls, minimal overhead
Cons: Manual binding maintenance, potential runtime errors

3. Native compilation/interop

The third approach is native compilation/interop, like Kotlin/JS. Since the code compiles to JavaScript, you can directly interface with JS:

external fun alert(message: String)
external val console: Console

fun main() {
    alert("Hello from Kotlin!")
    console.log("Direct JS access")
}

Pros: Natural integration, full ecosystem access
Cons: Compilation complexity, language semantic mismatches

For Hologram, interestingly, the third approach doesn’t translate that well. While Hologram does compile to JavaScript, it uses its own client-side Elixir runtime rather than generating idiomatic JavaScript. This means we’re running Elixir semantics on top of JavaScript, and the different syntax and data types between JavaScript and Elixir (atoms, tuples, pattern matching, immutable data structures) don’t have direct JavaScript equivalents.


What do you think? Which approach resonates most with your use cases?

jam

jam

At the moment, I’d vote 2. Seems simplest to me and feels like the most general / flexible which I think would be important. Though I would like to see some examples of 1 in the Hologram context.

Where Next?

Popular in Discussions Top

bartblast
With the core component system and HTTP/WebSocket infrastructure solid, it’s time to tackle Pub/Sub support. What We Have vs What’s Miss...
New
jdumont
I could write forever about this, but I’ll do my best to keep it succinct. For anyone familiar with event sourcing, what is your opinion...
New
Morzaram
Hey everyone. I’m feeling a bit conflicted. I’ve learned Flutter and built a somewhat MVP of this app. I’m a solo dev and throughout this...
New
bartblast
Hey there! :slight_smile: I’m working on updating the Hologram website home page and would love to get your input. Current situation: ...
New
ashkan117
I’m wondering how do people structure their JSON Api’s with Phoenix. Using the blogs example, let’s say I have a blogs view like the foll...
New
garrison
I have been thinking about how I might write a new web framework in Elixir. (Not committing to anything, just thinking about it.) One th...
New
bartblast
Some great comments in the home page thread shifted toward what you’d like to see in Hologram’s future, particularly standalone mode. I’v...
New
AstonJ
A remark @Garrison made… ..has already inspired a thread for the technical side of reclaiming our internet, but there is of course anot...
New
matreyes
I haven’t seen this paper being discussed by the community, but I think this makes Elixir more relevant than ever. TLDR; The paper...
New
PragTob
:wave: I’m currently extracting the statistics calculation part from benchee and stumbled upon how to present error conditions. In the c...
New

Other popular topics Top

senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 45766 226
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New

We're in Beta

About us Mission Statement