Macro to use .html.heex file for Phoenix.Component tempalte

Hey, I wrote a small macro to render .html.heex file as a template in a phoenix functional component. The usage and macro definitions are below. The basic approach is to insert the compiled heex template at compile time. It’s essentially a copy-paste of Phoenix.LiveView.Helpers.sigil_H. What would be the downsides of using this approach? Also, is there a plan to support rendering of .html.heex for stateless components, in the future?

The usage looks something like this:

defmodule AppWeb.BrandComponents do
  use AppWeb.Component.ComponentTemplateHelper

  def logo(assigns) do
    component_template("logo.html.heex")
  end
end

Here is the macro definition

defmodule AppWeb.Component.ComponentTemplateHelper do
  defmacro __using__(_info) do
    quote do
      import unquote(__MODULE__)
    end
  end

  defmacro component_template(rel_path) do
    # Not sure about the file, line, module options
    options = [
      engine: Phoenix.LiveView.HTMLEngine,
      file: __CALLER__.file,
      line: __CALLER__.line,
      module: __CALLER__.module
    ]

    file_path =
      __CALLER__.file
      |> Path.dirname()
      |> Path.relative_to_cwd()
      |> Path.join(rel_path)

    Module.put_attribute(__CALLER__.module, :external_resource, file_path)

    compiled =
      file_path
      |> File.read!()
      |> EEx.compile_string(options)

    quote do
      unquote(compiled)
    end
  end
end
2 Likes

This works in current LiveView.
It’s a good solution for longer components and also to be able to format both EX and HEEX files.

Is there any other downside in the meanwhile before an official solution?

To avoid warnings for variables not used we added:

defmacro component_template(rel_path, _extra \\ []) do

Component example:

  use LiveAdminWeb.Components.TemplateHelper

  def render(assigns) do
    locales = MgmtCompanies.get_ui_locales(assigns.user_subdomain)
    form = :localeChange

    form_class = [
      "form-component"
    ]

    component_template("components_locale.html.heex", [locales, form, form_class])
  end

Heex example:

<div id="globalLocale">
  <.form let={f} for={form} phx-change="locale-change" phx-target={@myself} class={form_class}>
    <%= HTMLForm.hidden_input(f, :path, value: @path) %>
    <%= HTMLForm.hidden_input(f, :current, value: @locale) %>
    <%= HTMLForm.select(f, :new, locales, value: @locale, class: "select-locale") %>
  </.form>
</div>