Dynamic Template Loading
Hi
I'm trying to build a collaborative wiki and I'd like to use Tera's template system. However some problems arise and I wonder if Tera can be used in this kind of use case.
The system is quite simple: a user can write a page that will be registered on a database (we are doing this because we are going to have a lot of pages). What I'm trying to build is the rendering server, which will fetch the template from the database and send the result of the rendering.
The first problem is that I don't have control over the template cache system: I'd like to implement a custom LFU strategy. This is currently impossible because even if Template is exposed, Renderer is not.
I'm imagining something that would look like this:
use tera::{Context, Renderer, Template, Tera};
fn main() {
// I use Tera for everything that is static and won't (probably) change like macro, base template...
let tera = Tera::new("./template/**/*.html").unwrap();
let name = "my-custom-page-slug-to-render";
// database
let raw = fetch(&name);
let result = {
let template = get_cached_template_or_generate_a_new_one(&name, &raw);
Renderer::new(template, &tera, Context::default())
.render()
.unwrap()
};
send(result);
}
Is that possible? Other problems appear in a more advanced implementation (module definition by users) but I want to discuss custom rendering first: I know that Template is only exported for Benchmarks etc, but isn't the use legitimate here?
Thanks,
Isn't that https://tera.netlify.com/docs/#loading-templates-from-strings ?
I have seen this but the problem is that I already know that we are going to have tens of thousands of pages in the database written by our users (this is already the case in the current system).
UPDATE: I updated the code in my previous comment, maybe it can be helpfull.
If I understand correctly, you have some custom templates, a main Tera instance and you want to be able to:
- add a raw template: already doable
- remove templates: not doable currently
In get_cached_template_or_generate_a_new_one, where/what would the cache be? Templates have to be added to a Tera instance to check for inheritance so your code sample won't work.
If the user templates don't use inheritance or anything like that, do they use anything from the Tera instance outside of the default filters/tests/functions?
Hi,
I don't know if I understood your message correctly. I will try to answer as accurately as possible. The purpose of using Tera in my case is to let the user write dynamic pages with Tera syntax. These pages are stored in the database and when a user will request a page from the system, the system will create the template and render it.
So from your comment I suppose this might be possible.
use tera::{Context, Renderer, Template, Tera};
fn main() {
// I use Tera for everything that is static and won't (probably) change like macro, base template...
let tera = Tera::new("./template/**/*.html").unwrap();
let name = "my-custom-page-slug-to-render";
// database
let raw = fetch(&name);
let result = {
let template = get_cached_template_or_generate_a_new_one(&name, &raw, &tera);
Renderer::new(template, &tera, &Context::default())
.render()
.unwrap()
};
send(result);
}
fn get_cached_template_or_generate_a_new_one(name: &str, raw: &str, tera: &Tera) -> Template {
// check cache w/ name
// if cached template is found: return it
// else create new Template w/ `tera` as Tera instance
// save it into the cache
// return it
}
the user will only be able to use include for static templates already compiled via Tera::new
Have I answered your questions?
Thanks,
The thing I don't understand is what is the cache there? Are you caching the output of Tera::render or the template itself? If it's just a LRU on the template themselves, I think adding a remove_template fn would allow you to build your own cache right?
It might work, but I think we'll test a basic LRU first and then go for a custom eviction strategy like a LFU that might require exposing the Renderer. Using the basic map hash might be too simplistic I think.
@Keats Hello
Following the last updates, I found a workaround with render_str, but this implies that Tera compiles the same template several times sometimes. Isn't it still possible to expose Renderer? It would make a good addition in conjunction with render_str.
I don't think the internals will be exposed as that would mean I can't do any breaking changes to it anymore.
Why wouldn't Render have the same statue as Template, which is exposed? I have to seem insistent, but for me it's all that Tera needs to be performant server side with dynamic data.
Template is public but considered private api (hidden from docs), Renderer could be made the same but that means that it could have breaking changes in any releases, without even being mentioned in the changelog.
I'm okay with that. Since no one before me had asked for this API, I think leaving it undocumented and unversioned is a good compromise.
Hi, during lockdown I'd like to do some work on Tera's server rendering w/ template in database. Is it still possible to publish Render?
I would take a PR for it
I also struct this problem.
After I've got a template value, e.g.:
let template: &Template = tera.get_template(format!("index.{lang}.html").as_str()) .unwrap_or( tera.get_template("index.html")? );
How can I render it?