DSL for creating html structure straight with Elixir blocks:
use WebAssembly
builder do
html do
head do
meta http_equiv: "Content-Type", content: "text/html"
title "example"
end
body do
div class: "container", id: :content do
ul do
for index <- 1..3, do:
li "item #{index}"
end
random = :random.uniform(10)
if random == 5 do
text "Lucky! You got five"
end
end
span [style: "smiling"], "that was nice"
end
end
end
This results in a deeply nested list (aka iolist) which you can flatten or (better!) send to the socket as it is (via Plug & Cowboy for example).
Now what can be concluded from the example above:
- you produce HTML elements by using macros inside
builder
block - non-void element can be used with "flat" content argument or with a
do
-block - element with a
do
-block means nesting - inside such a
do
-block you have access to full Elixir syntax - element attributes go first (but are optional), then the content
- attributes are Elixir keywords
- underscores in attribute keys are translated to dash signs
- you can omit brackets around attributes when using
do
-block, but not when using flat form - void HTML elements correspond to macros with attributes only,
like
meta
above - if you want to emit just text without surrounding html tags,
simply use
text
macro.
For me it's beautiful. What about you?
- to have views in pure Elixir, without HTML templates
- to utilize Erlang's approach: you can feed sockets with iolists instead of one big binary produced by template engine
You can possibly mix different styles: code small snippets in WebAssembly and feed them to your partial templates, finally using your template engine to render the whole page.
WebAssembly is published on Hex, so just add {:webassembly, "~> 0.6"}
to your deps and :webassembly
to your apps in the mix.exs
.
Using it with Plug is a no-brainer - you just pass the doc to send_resp/3
:
defmodule Plugged do
import Plug.Conn
use Plug.Router
use WebAssembly
plug :match
plug :dispatch
get "/" do
doc = builder do
html do
body do
text "hello from Plug!"
end
end
end
conn
|> put_resp_content_type("text/html")
|> send_resp(200, doc)
end
end
API details are available at hexdocs.
WebAssembly aims to have 100% test coverage.
As for releases 0.3.0
and above WebAssembly dialyzes with no warnings.
Run mix dialyzer
to validate locally.
Loosely inspired by Markaby.
The code is released under the BSD 2-Clause License.