FrancisTemplate.Engine behaviour (Francis Template v0.1.0)

View Source

Behaviour for pluggable template engines.

An engine receives the path to a template file and the assigns to render it with, and returns the rendered output as iodata (a binary is valid iodata).

The default engine is FrancisTemplate.EEx, registered for the .eex extension. Engines are resolved per-template by file extension, so multiple engines can coexist in the same application.

To use a different engine — for example an adapter for a Liquid implementation such as Solid, which is handy if you also write Shopify themes — implement this behaviour and register it for an extension:

defmodule MyApp.LiquidEngine do
  @behaviour FrancisTemplate.Engine

  @impl true
  def render(path, assigns) do
    path
    |> File.read!()
    |> Solid.parse!()
    |> Solid.render!(stringify_keys(assigns))
    |> to_string()
  end

  defp stringify_keys(assigns),
    do: Map.new(assigns, fn {k, v} -> {to_string(k), v} end)
end

# config/config.exs
config :francis_template, engines: %{"liquid" => MyApp.LiquidEngine}

Note that engines differ in how they interpret assigns: FrancisTemplate.EEx expects atom-keyed assigns exposed through the @ syntax, while a Liquid engine expects string-keyed data. Normalising the assigns is the engine's concern.

Summary

Callbacks

render(path, assigns)

@callback render(path :: String.t(), assigns :: map() | keyword()) :: iodata()