Skip to content

feat: replace Handlebars with Nunjucks in TEMPLATE renderer#198

Open
victoraraujo105 wants to merge 2 commits intoh-sphere:mainfrom
victor-software-house:feat/nunjucks-template-renderer
Open

feat: replace Handlebars with Nunjucks in TEMPLATE renderer#198
victoraraujo105 wants to merge 2 commits intoh-sphere:mainfrom
victor-software-house:feat/nunjucks-template-renderer

Conversation

@victoraraujo105
Copy link
Copy Markdown

@victoraraujo105 victoraraujo105 commented Feb 24, 2026

Summary

Replace the Handlebars template engine with Nunjucks in the TEMPLATE renderer to enable vault-based template reuse and provide a more expressive templating layer.

Motivation

The core problem: template reuse is impossible with Handlebars

Users who build custom table layouts in TEMPLATE blocks must duplicate the entire template in every code block. When multiple notes query similar data (e.g. task lists with Azure DevOps links, GitLab MR links, internal vault links), the same 20-30 line template is copied verbatim each time. Changing the layout means updating every copy.

The natural solution is to let users define templates in vault files and reference them via {% include %} or {% from ... import %}. This is architecturally impossible with Handlebars. Handlebars partials must be registered programmatically via Handlebars.registerPartial() before compilation — there is no loader interface that allows resolving templates from an external source at render time.

Why Nunjucks

Nunjucks (a Jinja2 port for JavaScript) has a native Loader architecture: its Environment constructor accepts a Loader object that resolves template names to source content. This is the exact extension point needed to load .njk files from the Obsidian vault. A follow-up PR (#199) implements this loader.

Beyond the loader architecture, Nunjucks also provides practical improvements for template authors:

  • groupby / unique filters — group and deduplicate data in the template instead of pushing complexity into SQL (GROUP_CONCAT, subqueries)
  • {% set %} variables — intermediate computations without extra SQL columns
  • {% macro %} definitions — reusable template functions within a single block
  • Expressions — arithmetic, comparisons, ternary inline in output tags
  • Jinja2 familiarity — widely known syntax (Python, Ansible, dbt, Hugo, Eleventy)

Syntax migration

Handlebars Nunjucks
{{#each data}}...{{/each}} {% for row in data %}...{% endfor %}
{{#if condition}}...{{/if}} {% if condition %}...{% endif %}
{{#unless x}}...{{/unless}} {% if not x %}...{% endif %}
{{this.field}} {{ row.field }} (explicit loop var)
{{@index}} {{ loop.index0 }}

Example

Before (Handlebars):

TEMPLATE
{{#each data}}
<p>{{title}} - {{state}}</p>
{{/each}}

After (Nunjucks):

TEMPLATE
{% for row in data %}
<p>{{ row.title }} - {{ row.state }}</p>
{% endfor %}

Changes

  • package.json: Replace handlebars dependency with nunjucks
  • TemplateRenderer.ts: Rewrite to use nunjucks.compile / nunjucks.runtime.SafeString. Add groupby and unique custom filters.
  • parser.ts: Rename grammar rule handlebarsTemplatenunjucksTemplate
  • nunjucksHighlighter.ts (new): Syntax highlighting for Nunjucks tags ({% %}), expressions ({{ }}), comments ({# #}), filters (|), and keywords
  • handlebarsHighlighter.ts (deleted): Replaced by nunjucksHighlighter.ts
  • highlighterOperation.ts: Import updated to use nunjucksHighlighter

Breaking Change

Existing templates using Handlebars syntax ({{#each}}, {{#if}}, {{#unless}}) must be updated to Nunjucks equivalents. The {{ variable }} output syntax remains identical — only block helpers and iteration syntax change.

Testing

  • Build passes
  • All 72 existing tests pass (no regressions)
  • Manual testing in Obsidian vault confirmed rendering with Nunjucks syntax

Follow-up

PR #199 adds a VaultLoader that enables {% include %} and {% from ... import %} to load .njk template files from the vault — the primary use case that motivated this engine swap.

Swap template engine from Handlebars to Nunjucks for richer template
capabilities. Nunjucks provides native groupby filter, macros,
set/variables, and recursive calls without SQL workarounds.

Changes:
- TemplateRenderer.ts: use nunjucks.compile/render, add groupby/unique filters
- nunjucksHighlighter.ts: syntax highlighting for Nunjucks tags/expressions
- parser.ts: rename handlebarsTemplate -> nunjucksTemplate in grammar
- package.json: swap handlebars dep for nunjucks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant