Phoenix.Template (phoenix_template v1.1.0)

Copy Markdown View Source

Templates are markup languages that are compiled to Elixir code.

This module provides functions for loading and compiling templates from disk. A markup language is compiled to Elixir code via an engine. See Phoenix.Template.Engine.

In practice, developers rarely use Phoenix.Template directly. Instead, libraries such as Phoenix.View and Phoenix.LiveView use it as a building block.

Custom Template Engines

Phoenix supports custom template engines. Engines tell Phoenix how to convert a template path into quoted expressions. See Phoenix.Template.Engine for more information on the API required to be implemented by custom engines.

Once a template engine is defined, you can tell Phoenix about it via the template engines option:

config :phoenix_template, :template_engines,
  eex: Phoenix.Template.EExEngine,
  exs: Phoenix.Template.ExsEngine

Format encoders

Besides template engines, Phoenix has the concept of format encoders. Format encoders work per format and are responsible for encoding a given format to a string. For example, when rendering JSON, your templates may return a regular Elixir map. Then the JSON format encoder is invoked to convert it to JSON.

A format encoder must export a function called encode_to_iodata!/1 which receives the rendering artifact and returns iodata.

New encoders can be added via the format encoder option:

config :phoenix_template, :format_encoders,
  html: Phoenix.HTML.Engine

HTML formats

.html.eex templates are compiled and encoded with Phoenix.HTML.Engine, which provides HTML safety. Other formats are compiled with EEx.SmartEngine, which interpolates values as is.

A format that renders HTML-like markup but needs its own encoder, for example one that post-processes the rendered markup, can be compiled with Phoenix.HTML.Engine too by listing it in the :html_formats option:

config :phoenix_template, :format_encoders, mjml: MyApp.MJML
config :phoenix_template, :html_formats, [:html, :mjml]

Its templates are then compiled exactly like .html.eex ones. Interpolated values are escaped unless they are marked as safe, such as with Phoenix.HTML.raw/1, the :trim_on_html_eex_engine option applies, and the format encoder receives the {:safe, iodata} tuple that they return:

defmodule MyApp.MJML do
  def encode_to_iodata!({:safe, mjml}), do: MyApp.MJML.to_html(mjml)
end

In case the {:safe, ...} tuple is not received, you should raise, as it means the user likely has not configured the html_formats accordingly.

This requires phoenix_html as a dependency.

Summary

Functions

Ensure __mix_recompile__?/0 will be defined.

Compiles a function for each template in the given root.

A convenience macro for embeding templates as functions.

Returns a keyword list with all template engines extensions followed by their modules.

Returns all template paths in a given template root.

Returns the format encoder for the given template.

Returns the hash of all template paths in the given root.

Renders template from module.

Renders the template and returns iodata.

Renders the template to string.

Types

path()

@type path() :: binary()

root()

@type root() :: binary()

Functions

__using__(opts)

(macro)

Ensure __mix_recompile__?/0 will be defined.

compile_all(converter, root, pattern \\ "*", engines \\ nil)

(macro)

Compiles a function for each template in the given root.

converter is an anonymous function that receives the template path and returns the function name (as a string).

For example, to compile all .eex templates in a given directory, you might do:

Phoenix.Template.compile_all(
  &(&1 |> Path.basename() |> Path.rootname(".eex")),
  __DIR__,
  "*.eex"
)

If the directory has templates named foo.eex and bar.eex, they will be compiled into the functions foo/1 and bar/1 that receive the template assigns as argument.

You may optionally pass a keyword list of engines. If a list is given, we will lookup and compile only this subset of engines. If none is passed (nil), the default list returned by engines/0 is used.

embed_templates(pattern, opts \\ [])

(macro)

A convenience macro for embeding templates as functions.

This macro is built on top of the more general compile_all/3 functionality.

Options

  • :root - The root directory to embed files. Defaults to the current module's directory (__DIR__)
  • :suffix - The string value to append to embedded function names. By default, function names will be the name of the template file excluding the format and engine.

A wildcard pattern may be used to select all files within a directory tree. For example, imagine a directory listing:

├── pages
│   ├── about.html.heex
│   └── sitemap.xml.eex

Then to embed the templates in your module:

defmodule MyAppWeb.Renderer do
  import Phoenix.Template, only: [embed_templates: 1]
  embed_templates "pages/*"
end

Now, your module will have a about/1 and sitemap/1 functions. Note that functions across different formats were embedded. In case you want to distinguish between them, you can give a more specific pattern:

defmodule MyAppWeb.Emails do
  import Phoenix.Template, only: [embed_templates: 2]

  embed_templates "pages/*.html", suffix: "_html"
  embed_templates "pages/*.xml", suffix: "_xml"
end

Now the functions will be about_html and sitemap_xml.

engines()

@spec engines() :: %{required(atom()) => module()}

Returns a keyword list with all template engines extensions followed by their modules.

find_all(root, pattern \\ "*", engines \\ engines())

@spec find_all(root(), pattern :: String.t(), %{required(atom()) => module()}) :: [
  path()
]

Returns all template paths in a given template root.

format_encoder(format)

@spec format_encoder(format :: String.t()) :: module() | nil

Returns the format encoder for the given template.

hash(root, pattern \\ "*", engines \\ engines())

@spec hash(root(), pattern :: String.t(), %{required(atom()) => module()}) :: binary()

Returns the hash of all template paths in the given root.

Used by Phoenix to check if a given root path requires recompilation.

module_to_template_root(module, base, suffix)

This function is deprecated. Use Phoenix.View.module_to_template_root/3.

render(module, template, format, assigns)

Renders template from module.

For a module called MyApp.FooHTML and template "index.html.heex", it will:

  • First attempt to call MyApp.FooHTML.index(assigns)

  • Then fallback to MyApp.FooHTML.render("index.html", assigns)

  • Raise otherwise

It expects the HTML module, the template as a string, the format, and a set of assigns.

Notice that this function returns the inner representation of a template. If you want the encoded template as a result, use render_to_iodata/4 instead.

Examples

Phoenix.Template.render(YourApp.UserView, "index", "html", name: "John Doe")
#=> {:safe, "Hello John Doe"}

Assigns

Assigns are meant to be user data that will be available in templates. However, there are keys under assigns that are specially handled by Phoenix, they are:

  • :layout - tells Phoenix to wrap the rendered result in the given layout. See next section

Layouts

Templates can be rendered within other templates using the :layout option. :layout accepts a tuple of the form {LayoutModule, "template.extension"}.

To template that goes inside the layout will be placed in the @inner_content assign:

<%= @inner_content %>

render_to_iodata(module, template, format, assign)

Renders the template and returns iodata.

render_to_string(module, template, format, assign)

Renders the template to string.

template_path_to_name(path, root)

This function is deprecated. Use Phoenix.View.template_path_to_name/3.