SWAFViews (swaf_views v0.2.0)
SWAFViews is a template library dedicated to HTML generation. It only depends on EEx. It precompiles templates as functions for fast rendering and protects the rendered code from injection.
Getting started
SWAFViews scans a hierarchy of directories looking for .html.eex
files. For every directory it traverses, it creates a module named
after that directory. It finally generates a function named after
the name of the template file (see below).
Install it as a dependency
To use SWAFViews in a project, first include it as a dependency in
your preject's mix.exs file:
defp deps do
[
# if you want to play with the source code and contribute
# {:swaf_views, path: "../swaf_views"},
{:swaf_views, "~> 0.2"}
]
endDefine the root module for the templates
Then define an .ex file that will be the root for the module
hierarchy of the templates. For exemple:
# file: lib/my_app/web/views.ex
defmodule MyApp.Web.Views do
use SWAFViews,
template_dir: "templates"
endAll the functions and modules will be injected below
MyApp.Web.Views.
template_dir defines where the template are located. It is the
only parameter and it is mandatory. It has to point to an existing
directory.
With the previous configuration, the templates are in the templates
directory at the root of the project.
Create a set of templates
Templates are .html.eex files with eex syntax (we'll get on the
content of the template files below). They are located in a
hierarchy of directories. Each sub-directory will generate a
sub-module. Files need to end with .html.eex. Files and
directories prefixed with _ won't be collected. See the compiler
output below.
templates/
├── index.html.eex
├── _index2.html.eex
└── partials
├── footer.html.eex
├── header.html.eex
└── header.html.eex~With the hierarchy above, some of the functions that will be created are:
MyApp.Web.Views.index()MyApp.Web.Views.Partials.header()- etc
Each function comes in two versions, func/0 and func/1. func/1
accepts a map that will be made available for the template in the
assigns variable. func/0 is a convenience function where the
parameter defaults to %{}.
Call of template functions in controller's action
defmodule MyApp.Web.Controller.PageController do
alias MyApp.Web.Views
require Logger
alias Plug.Conn
def index(conn) do
params = conn.assigns
|> Map.merge(%{params: conn.params})
|> Map.merge(%{a: 4, b: 12})
conn
|> Conn.put_resp_content_type("text/html")
|> Conn.send_resp(200, Views.index(params))
end
endCompile the application and the templates
For the time being, when a new template is defined, you need to quit
iex and run mix compile or iex -S mix. However, if an
exeisting template is modified, yoiu can call recompile in the
REPL.
$ iex -S mix
[... some output ...]
==> my_app
Compiling 2 files (.ex)
-- Compiling templates from directory 'templates'
** Ignoring '"templates/partials/footer.html.eex~"' (not a .html.eex file)
** Ignoring '"templates/_index2.html.eex"' (underscored "_index2.html.eex")
-- Compiling template from file 'partials/footer.html.eex'
-- Compiling template from file 'partials/header.html.eex'
-- Compiling template from file '/index.html.eex'
Generated my_app app
Generated template functions
As said previously, the compiler generates two versions of each
function. For the template file, say, templates/index.html.eex,
the compiler will generate:
MyApp.Web.Views.index/1: this function accepts a map which will be passed inside the template as theassignsparameter. In a controller, it can be called as:Conn.send_resp(200, Views.index(%{name: "Polo", title: "The title of the page"}))Then, inside the template, we can get the parameters with the usual
@<key>syntax:Hi <%= @name %> <p/> The title of this page is <%= @title %>Notice that the
assignsmap is sanitized against XSS injection before it is passed to a template function.MyApp.Web.Views.index/0: is function a convenience function which actually is equivalent to the callMyApp.Web.Views.index(%{})
Notice that the assigns map is sanitized against XSS injection
before it is passed to a template function.
Content of the template files
The template files are .eex files so please refer the the EEx
official documentation.
Few points to notice:
The syntax
@some_keyworks ifsome_keyis an atom in theassignsmap. If a key is has some other type, say a binary, use<%= assigns["key"] %>syntax.A template can be called from within another template. In this case the full name is required. For exemple:
<%= MyApp.Web.Views.Partials.header(assigns) %> <center> This is the body of the page </center> <%= MyApp.Web.Views.Partials.footer(assigns) %>