Repository metrics
- Stars
- (53 stars)
- PR merge metrics
- (PR metrics pending)
Description
In Nunjucks and Jinja, the macro tag is the closest we can get to functional programming with templates, and is a much clearer and succinct way of handling defaults than the convention of components or partials expecting specifically named, global template variables. For instance, to create a nested list component without macros, you end up doing something like this:
<ul>
{% for item in links %}
<li><a href="{{ item.href }}">{{ item.text }}</a>
{% if item.links %}
{% set links = item.links %}
{% include 'list.html' %}
{% endif %}
</li>
{% endfor %}
</ul>
...which is clunky and brittle because:
- As a user of the component or partial, you have to find the
forloop in order to know that it expects thelinksvariable to be set, and trust that none of your other templates reference that variable. - If the component maintainer has to change the variable name for whatever reason, all of the templates that reference it need to be changed, too.
- The
includeneeds to reference the full path to the template within the environment path(s).
The solution is something much more elegant:
{% macro list(links) %}
<ul>
{% for item in links %}
<li>
<a href="{{ item.href }}">{{ item.text }}</a>
{% if item.links %}{{ list(item.links) }}{% endif %}
</li>
{% endfor %}
</ul>
{% endmacro %}
I'm not sure what compatibility would look like for other languages, but here's a first pass:
-
Jekyll could do this with include parameters, e.g.
{% include list.html links=item.links %} -
ERB might be tricky because I'm not sure if it's valid to define a function and break it up with delimiters like this:
<% def list(links) %> <ul> <% for item in links %> <li> <a href="<%= item.href %>"><%= item.text %></a> <% if item.links %><%= list(item.links) %><% end %> </li> <% end %> </ul> <% end %> -
Twig has macros, but PHP would need to look more like ERB.
-
I'm pretty sure that Handlebars would require registering a helper in JS. ☹️