RBlade: a templating engine for Rails

I’ve just started using rails, having had a background working with PHP and Laravel. One of the things I really missed from Laravel was the Blade templating engine because its syntax is so clear and easy to use.

As such, I’ve created RBlade, a templating engine inspired by Laravel’s Blade.

<!-- app/views/application/index.rblade -->
<x-paragraph class="text-lg">
  <x-slot::heading class="text-xl">RBlade Example</x-slot::heading>
  This example shows some examples of <strong>RBlade</strong>: HTML-like components, passing in block-level HTML and text, and helpful directives like "@if".
</x-paragraph>

<!-- app/views/components/paragraph.rblade -->
@props(heading: false)
@if (heading)
  <h3 {{ heading.attributes }}>
    {{ heading }}
  </h3>
@endif
<p {{ attributes }}>{{ slot }}</p>

<!-- Compiles to -->
<h3 class="text-xl">
  RBlade Example
</h3>
<p class="text-lg">
  This example shows some examples of <strong>RBlade</strong>: HTML-like components, passing in block-level HTML and text, and helpful directives like "@if".
</p>

There are a number of great features, but I find stacks particularly useful. Stacks allow you to push content to a “stack” from almost anywhere in a template, including in components and after the stack is created. This make it easy to include JS scripts on demand, for example:

<!-- app/views/application/index.rblade -->
@stack('scripts')
...
<x-some-js-component/>
...
<x-some-js-component/>

<!-- app/views/components/some-js-component.rblade -->
@pushOnce('scripts')
  <script src="/js/js-component.js"></script>
@endPushOnce
...

<!-- When the view is rendered, @stacks will output: -->
<script src="/js/js-component.js"></script>

In terms of performance, although RBlade is more syntactically complicated than ERB templates, much of the processing is done on the first compile, which is then cached by Rails. As such, in my testing RBlade is almost on-par with other templating engines for single-file templates, but noticeably faster when using multiple partials within a template (or components in RBlade’s case).

I know this won’t be for everyone, but I hope this appeals to some, and I’m open to any and all suggestions and bug reports. The project repository contains comprehensive documentation of RBlade, including a quick reference.