Hologram - full stack isomorphic Elixir web framework

Interesting! What are you using to transpile Elixir, elixirscript?

1 Like

Wow, this is really cool! Would love to see a “real” project with this to get an idea of how to structure things.

1 Like

@christhekeele I initially tried to use ElixirScript, but I couldn’t make it work. When I went through its GitHub issues I realized the creator stopped maintaining the project and focused all of his efforts on Lumen: Still alive? · Issue #495 · elixirscript/elixirscript · GitHub So I tried Lumen, but too much work was in progress. And now it looks that the project is stalled at the moment: Project Status · Issue #698 · lumen/lumen · GitHub

I also tried another route: Erlang → PureScript → JavaScript through Erlscripten, Erlscripten – Transpiling Erlang to Javascript. Yes, you read it right - News and Announcements - æforum but I wasn’t convinced with it, because one of my goals was easy debugging of the transpiled code, and for that it helps if the transpiled code resembles what was actually written in Elixir.

So I decided to write my own transpiler, because that gives me much more control over the output code and I can fix any errors myself. I do this by first converting the code to AST, then building IR (intermediate representation) containing context and metadata, which makes it easier to reason about the code and finally the IR is encoded into JavaScript. You can take a glance at its structure here: hologram/lib/hologram/compiler at master · segmetric/hologram · GitHub

7 Likes

@tommica Thanks! :slight_smile: I’m building a website that will have a basic getting started guide with installation instructions. I’ve been also thinking about creating a basic demo project. Do you have any ideas for that?

1 Like

Very cool. Can the pre-transpiled code run in elixir for testing purpose? One of the pain point of LV is that it is hard to do testing the cover the client side functionalities too.

1 Like

@derek-zhou If I understand correctly what you mean, then yes, it should be possible.
You could theoretically run the whole event loop in Elixir, e.g. some action triggers some command, which then triggers some other action, and the new state is used to rerender - all of this can be executed inside tests. You can also simulate some browser use without E2E tests, by triggering events directly (without the DOM) through tests. Is that what you meant?

2 Likes

Not sure if the goal was for the API to be closer to elm than elixir, but maybe action and command could be switched to handle_call and handle_cast to be closer to elixir conventions. Love the project btw

1 Like

I love the route annotation (route "/my-page-path")! I wanted to do this for a toy framework I was working on, but the whole problem of how to aggregate those routes at compile-time (if you aggregate those routes at compile-time) is very non-trivial; I see you did quite a bit to accommodate that!

Also when I was investigating this, it was pointed out to me that any such work done at compile-time will not apply to “pages” added at runtime, e.g. by a hot code reload, unless you explicitly write some hooks to do that. Just some food for thought.

Good luck, I wish you tremendous success!

1 Like

Any plans to split out the transpiler into a separate library?

Yes. Being able to run regression tests without needing a javascript counterpart or a fake browser is huge.

I am looking forward for a detailed write up of how to do this. Keep up with the good work!

1 Like

Maybe a simple forum could be interesting - has registration/login, storing and retrieving from database, and maybe even roles and permissions.

3 Likes

Congrats, this looks very promising. What will be Hologram’s main selling points over a standard liveview app? developer productivity, ergonomics, simplicity, other…?

1 Like

@Un3qual Hey, thanks - good suggestion! I initially considered to use handle_call/handle_cast but later switched to handle_action/handle_command and finally to action/command.

My reasoning is as follows:

  • handle_cast/handle_call convention is related to GenServer and the wording makes sense in the context of client-server. Hologram pages/components/layouts are just plain modules, not GenServers.
  • One of my main goals with Hologram is to be as intuitive and simple as possible, also to devs that have converted to Elixir just recently. And I feel that action/command is much closer to the intention of the code. Besides it’s shorter and have the same meaning even without using the handle_ prefix.

I’m happy to reconsider that in some time though, based on user feedback :slight_smile:

3 Likes

@J3RN I believe I encountered similar problems :slight_smile: The way I solved that was by assembling a custom router dynamically in runtime during the app startup - once all page modules are compiled and Hologram can determine what routes are needed. It can be redefined dynamically as well (in case code reloading is needed).

@stevensonmt Yeah, I’ve got this at the back of my mind from the beginning. To do that I want to first support most of the Elixir syntax, and then some refactor would be needed, because it got coupled to the framework a little too much (but nothing that can’t be refactored).

1 Like

@Twfo326 Thanks! Here are the main selling points:

  • State on the client - and all of the problems that get solved by this approach (below)…

  • No latency issues as most of the code is run immediately on the client. This makes it possible to create rich UI or even games. At the moment with LiveView you need something like fly.io to make it bearable, but you still have latency and can’t guarantee the response time (there is always some variance). And you still need some JS or Alpine to make it work. Until someone manages to create quantum internet (e.g. by taking advantage of entanglement), there are no workarounds for this problem. Not sure if this is even technically possible, though :wink:

  • Better offline support (internet connection loss, poor signal, etc.). Since most of the code is run on the client and you only hit the server to run some command from time to time, Hologram can work offline most of the time. This would also make it possible to create PWA’s or mobile apps through WebView, assuming you use something like LocalStorage.

  • Less server RAM used - state is kept in the browser instead of the socket.

  • Less CPU used - most of the code is run by the browser not by the server.

  • Less bandwidth used - only commands need to communicate with the server, no need to send diffs to rerender components.

  • No state sync problems - state is kept only in one place (browser) and the websocket communication used is stateless.

  • No JS or Alpine.js needed except for communication with some third party scripts or widgets, but this can also be solved by creating some standardized libs for popular packages that would handle the interop.

Another important selling point is the dev experience. I envision Hologram to be very friendly to new Elixir converts or beginner devs. I want it to be very, very intuitive, so that you can focus on working on new features in your project instead of solving technical problems and writing boilerplate code.
To achieve that Hologram will provide out of the box such things as UI component library (CSS framework agnostic), authentication, authorization, easy debugging (with time travel), caching, localization and some other features that you typically use in a web app.

I think that using Hologram’s approach, i.e. Elixir-JS transpilation, code on client and action/command architecture it’s possible to create something as productive as Rails, but without its shortcomings related to scalability, efficiency, etc.

20 Likes

Really promising … many thanks!

Where would you like to discuss feedback without raising a github issue?

eg package {:hologram, “~> 0.1.0”} appears to be missing lib/mix/tasks/compile.hologram.ex,
or am I misunderstanding how the package should be used standalone from hologram/e2e?

1 Like

Hey @gregjohnson, thanks! :slight_smile:

What do you suggest to use for feedback - this forum, GitHub issues, anything else?

Good catch - version 0.1.0 is missing lib/mix folder, but if you use the version from git master branch:
{:hologram, git: "https://github.com/bartblast/hologram.git"}
it should be included.

There are a few steps that need to be done to integrate Hologram into a standalone project, I will write detailed instructions for that very soon (it’s not that complicated, but I need to verify a few things first). I haven’t had much time recently, because I’ve been focusing on job interviews.

1 Like

@bartblast @christhekeele I stopped working on elixirscript mostly because it seemed like it wasn’t providing the value to the community I hoped it would. And bringing the BEAM to the browser is a big task in itself. But sounds like there is some interest in that sort of thing. I’d be interested in helping with an effort for having elixir compile to js. Nx and Gleam’s JS compiler makes me think going in a similar direction would be a good start since you don’t have to solve the BEAM in the browser so much.

4 Likes

That would be awesome @bryanjos! I’d love to use your help.

2 Likes