A Markup Generation Tool for Elixir
On Friction and Context Switching
When I’m coding up an application, it’s easy for me to get hung up on things that cause friction. For me, personally, having to write templates is a pain. It’s enough to make me want to stop working on something and check my email instead. For someone prone to distraction, this is not good.
I do not like having to context switch between code and templating. One second I am thinking in Elixir, and then the next I am thinking in HTML. Once again, I am back to Elixir. My brain doesn’t like this. I get especially annoyed when I just want to do some simple looping and I have to add markers for <%= dropping into Elixir %> and back out again. I have data. I have functions. I have ways to compose these things, enumerate, and chain them together. Please let me stay in the code, especially because Elixir naturally lends itself to structured representations.
So, I wrote a library.
The design had two basic requirements:
- Simple Elixir-based generation of tag-based markup.
- Interoperate properly with Phoenix helpers.
I looked at and tried a few similar libraries (Eml, Marker), but either wasn’t able to get them to work with Phoenix helpers, or had problems with their approach (usage of @tag syntax in templates where it didn’t refer to a module attribute). My goal was to keep things simple.
Taggart lets you express things like HTML, XML, and SGML using simple Elixir block syntax. Taggart supports a number of different call styles:
You can nest and combine in expected ways:
Taggart produces Phoenix-compatible “safe” html through underlying usage of the
Phoenix.HTML.content_tag/2. Since it just produces IO lists, it should remain compatible with any other library that uses the same format.
You can embed Taggart inside Phoenix helpers using
Taggart.taggart/1 to create IO List without creating a top-level wrapping tag.
You can also use Phoenix helpers intermingled with Taggart:
Phoenix views are just functions, so it’s possible to use pattern matching directly in a view to render your pages.
Performance-wise, Taggart is decent, but it can be better. Elixir means that templates render in microseconds, but it is still about 3x times slower than the equivalent Eex. For me, this is still a win. I am using it for things like dashboards where rendering performance is not the primary concern.
It currently relies on macro expansion to make calls to the underlying
Phoenix.HTML.content_tag/2 helper. As such, the bulk of the work is spent making calls to and within this function.
I have ideas for improving the performance of the library — by doing ahead of time compilation (similar to what Marker currently does) or by translating into Eex first and leaning on that project’s compilation. Contact me if you would like to help add this feature!
You can find the source code on GitHub.
This is still a new project. I expect issues to crop up here and there with the API, with performance, etc. Please provide feedback and error reports in the GitHub issues section for the project.
I hope you find it useful!
Update (November 25, 2017): I just discovered WebAssembly as well. I might not have created this had I seen that first. Still, I think the macro-driven approach I take has some advantages over the agent-based context that project seems to be using. I looked long and hard for projects like this. Elixir still needs a better discovery mechanism for this stuff. :/