Loading ECR templates at runtime*

I’ve been doing a bit of a dive into how ECR works, and ended up implementing a way to reload the non-code parts of ECR files at runtime. This means you can make an HTML template, tweak styles/layout and see the changes immediately, so long as you don’t touch any Crystal code in the template.

You can see the code here as part of my assortment of helper functions, bundled together as Geode.

I’ve also written a bit on how I got here; it started with me realising I was wasting effort allocating strings in HTML.escape just to immediately write it to an IO. I found this by profiling the code using Samply.

That lead me to design a way to make ECR templates HTML-safe by default, since littering HTML.escape everywhere is annoying.

Once I knew how ECR works (it’s really cool!) I realised I could load the template-y parts of the ECR file at runtime, which gives me most of the benefit of runtime templates while still being able to compile to efficient code (sans hot reloading) on a release build. That post also has a bit of explanation on why ECR is so cool.

Hopefully someone finds this useful or my explanations interesting!

9 Likes

Removing the non-IO API isn’t a good move here, since you’ll just encourage people to do this:

escaped = String.build { |io| HTML.escape(value, io) }

Honestly as a thought experiment it would be interesting if all string allocations had to be explicit like this instead of hidden, given how impactful they are on performance. (Maybe room for an ameba rule?)

I think a lint check that checks for useless string allocations that immediately get written to a IO would be great (I don’t know if ameba does this already).

As I said in the first post, I like APIs that you can progressively enhance, so I don’t have to write fully productionised code immediately or put up with tonnes of boilerplate to get things done easily. This is something I think Crystal does really well.

This is one of my frustrations with Rust—it’s harder to get something working, I just end up cloning all over the place and then cleaning stuff up later. (To be fair I haven’t done that much Rust, so this would probably get easier with more experience).

1 Like