I’m currently making a blog engine for my own use. It has Distillery releases, and is very configurable with the new Distillery config provider. The user can also reverse proxy it with Nginx and serve their own JS and CSS files, if they want to do so. So it should be usable for someone else than me as well, except… templates.
The HTML (and XML for RSS) templates use the EExHTML library and they are compiled in to the app as view functions. This means that a user must compile their own version if they want to change a template. If it was made with Phoenix or Plug, the same thing would happen, as releases are compiled beforehand.
Now (disregarding all the other differences) with PHP, it was very easy for a user to take an app and customise a single PHP file. I realise Elixir does not work this way, but I’m wondering if there is any way to accomplish something similar. Say you had to implement a feature where a user could put their own EEx files into a directory and reboot the release, and the release would pick up the new files and use them instead of the built in templates. How would you accomplish that? You would have to compile the templates at runtime and reload the corresponding modules somehow.
What I’m after is a blog engine where the user can customise any templates they want without compiling their own release. Just get the premade release from GitLab/where-ever, put your own files in a path, and boot it. Does this give anyone any ideas?
Store a reference to the module containing a specific template’s function, for example Mebe.Web.Templates.Foo.
When told to reload template, compile template with EEx (and configured EEx engine) into a new module with unique name, like Mebe.Web.Templates.Foo.V2. If compilation fails, don’t proceed, but log error instead.
Update stored module reference to point to new modules, other processes would be passed or would obtain this module reference somehow.
If it is for things like blogs, you can cache the result of the rendered template instead.
You don’t need to version it because Elixir modules are versioned in the VM due to hot code reloading. Just keep in mind that this will leak atoms but it is fine if only “admins” can do that.
This is true, but I was hoping to avoid that, because the use case might be different from a blog too. And even blogs have things like comments. It also would not work for partials that are called in loops with different inputs for each iteration.
I can recompile and reload the same module without compiling to a different version first? When do the other processes pick it up, when they make their next call into it? If a compilation error happens, I assume the old version of the module will remain?
Yeah I don’t think people will reload the templates that often, but of course it needs to be measured and taken into consideration, thanks for the reminder.
Immediately on the next fully qualified call to it (ModuleName.function(...)), and yes. Specifically the system keeps around 2 copies of each module that is hot-loaded until no more active references (actively running code) exist to the older one, if there ‘would be’ an even older one than any code actively running it would be killed (and the supervisor would restart it with the new code), but for that to happen in general usage you are either looping manually and near infinitely or you are hot-code reloading new versions extremely rapidly.