Blog

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 ```elixir 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 elixir 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)