Elixir-y goodness from front to back with Elixirscript
Elixir is an amazing language for the backend. Erlangs BEAM VM gives it a battle tested, highly reliable, functional base. Pattern matching is a joy and OTP offers tried and true answers to concurrency, scalability and uptime challenges. Mix in Elixirs pleasant ruby-like syntax, the lovely |>
pipeline operator and zero-cost abstractions with hygienic macros and the result is a cocktail I could drink all day, every day.
Isn’t it a shame we have to fall back to the less sophisticated taste of JavaScript when dealing with the frontend? That’s like pouring a dram of Laphroaig An Cuan Mor single malt whisky, then blending it with coke. The blasphemy!
Enter Elixirscript
Thanks to bryanjos’s brainchild Elixirscript you won’t have to. Save for some (current) limitations it lets you write Elixir on the frontend to your heart’s content. While it’s still very much in development you can already do quite a lot with it.
Boilerplate
If you want to get up and running quickly the elixirscript-project-boilerplate will help you on your way. It sets you up with babel and webpack so you can start writing your code instantly.
Phoenix integration
For a full stack experience the elixir_script
package integrates elixirscript with the phoenix framework. This hooks in to Phoenix’s brunch configuration to give you automatic recompilation and live reloading in the browser. To configure it we need to make sure the following is present:
in mix.exs
def project do
[
app: :my_first_app,
# Other stuff...
compilers: [:phoenix, :gettext, :elixir_script] ++ Mix.compilers,
elixir_script: [
# These paths will change when phoenix 1.4 is released
input: "web/static/elixirscript",
output: "web/static/js/build"
]
]
end
#...
defp deps do
[
# Other dependencies...
{:elixir_script, "~> 0.26.1"}
]
en
in config/dev.exs
config :expoker, Expoker.Web.Endpoint,
#...
watchers: [
node: [
"node_modules/brunch/bin/brunch", "watch", "--stdin", cd: Path.expand("../assets", __DIR__)
],
mix: ["elixirscript.watch"]
]
Elixirscript in practice
Easy interoperability
Calling javascript from elixirscript couldn’t be easier. Logging to console can be done with :console.log("Hello")
. This is similar to the way erlang interop works. Using dependencies is also a breeze. Just npm install
(or, preferably, yarn add
) your dependencies and define them in your mix.exs
(or pass them in the command line):
[input: "lib/frontend",
output: "assets/js/build",
js_modules: [
{React, "react"},
{Socket, "js/socket"}]]]
Reusing code
Elixirscript transpiles your regular .ex
files. This allows you to reuse your code between frontend and backend. Do be aware not to use elixir dependencies in shared files. Also left = right matching isn’t quite there yet so you might need to make some small modifications.
A simple usecase for this is validating forms in your frontend before sending them to the server:
defmodule President do
defstruct name: nil
def valid?(president) do
president.name != "Donald Trump"
end
end
bernie = %President{name: "Bernie Sanders"}
President.valid?(bernie) === true
What would be awesome is when you have an event-sourced system reusing event handlers in the frontend to optimistically apply state while the backend is still processing. But that’s a story for another time!
React views
There is some discussion going on about how to integrate JSX with elixirscript but it’s not there yet. In the meantime it’s trivial to implement a nice DSL using the power of macros as we can see in elixirscript_react (Note that it uses a slightly outdated version of elixirscript). Implementing a DSL for React as r.ex allows you to write react components like this:
def view(model) do
div do
form do
input [type: "text", placeholder: "Name", onChange: &update(&1, :name), value: model.name]
input [type: "email", placeholder: "Email", onChange: &update(&1, :email), value: model.email]
end
end
See the full example in app.ex. Those familiar with Elm will notice some similarities with The Elm Architecture which feels more natural in a functional language than React’s way of doing things.
Looking ahead
I’m looking forward to Elixirscript hitting a higher level of feature parity and stability. As Elixir hits the mainstream lets see if it will get more attention as well. Until now it has mostly been the work of bryanjos. Do checkout the elixirscript organization on Github. There’s the elixirscript repository, the tailored repo implementing elixir style patternmatching in javascript, elixir-estree implementing the AST from the EStree spec and some loaders and example projects.
I’m planning on playing around with elixirscript some more and hope to be able to contribute. Directions I’m interested in:
- Targeting WebAssembly
- ReactNative + Elixirscript
- Code reuse (CQRS/ES)