sunng87 / handlebars-iron

Handlebars middleware for Iron web framework
MIT License
119 stars 20 forks source link

FR: Improve usage for inlined templates #18

Closed untitaker closed 8 years ago

untitaker commented 8 years ago

I'm currently writing an application that should run as a single binary. Right now I'm acquiring the RwLock for the registry explicitly, and call register_template_string(..., include_str!(...)) for each template.

I've found two rather easy to fix usability problems specific to my usecase:

And then the idea of loading/parsing/compiling templates at compile-time comes to mind, but I suspect that the necessary APIs aren't stable yet in Rust, and that it's too late for those kind of major feature requests.

Regarding the two usability problems, I am not sure what to do. Perhaps HandlebarsEngine could make the prefix and suffix fields of type Option<String> to indicate that the raw registry should be used? Such a state would also disallow usage of reload and disable its initial invocation.

sunng87 commented 8 years ago

This has been my concern for a while. I was thinking about decoupling the directory scan from HandlebarsEngine, making the HandlebarsEngine a simple wrapper of handlebars that just doing middleware things well.

And we will introduce a DirectorySource trait (or struct ) that allows you to add a directory of templates to HandlebarsEngine. Features like reload/watch will be available to DirectorySource only. Then DirectorySource manages to add/remove templates to HandlebarsEngine.

With this design, the DirectorySource will be optional to HandlebarsEngine and you will be free to register template string manually.

This will be a breaking change but during 0.x releases we can do it aggressively to archive better design, just like Rust did. WDYT?

untitaker commented 8 years ago

Your plan sounds sensible. I guess that means that HandlebarsEngine::from will only take a registry as input (unless new features are added)

On Sun, Nov 01, 2015 at 06:54:01PM -0800, Ning Sun wrote:

This has been my concern for a while. I was thinking about decoupling the directory scan from HandlebarsEngine, making the HandlebarsEngine a simple wrapper of handlebars that just doing middleware things well.

And we will introduce a DirectorySource trait (or struct ) that allows you to add a directory of templates to HandlebarsEngine. Features like reload/watch will be available to DirectorySource only. Then DirectorySource manages to add/remove templates to HandlebarsEngine.

With this design, the DirectorySource will be optional to HandlebarsEngine and you will be free to register template string manually.

This will be a breaking change but during 0.x releases we can do it aggressively to archive better design, just like Rust did. WDYT?


Reply to this email directly or view it on GitHub: https://github.com/sunng87/handlebars-iron/issues/18#issuecomment-152896906

untitaker commented 8 years ago

What about moving the whole directory-watching feature into handlebars-rust?

sunng87 commented 8 years ago

I prefer to keep handlebars-rust to do parse/render things monolithically. Adding directory scanning and watching makes it heavy.

sunng87 commented 8 years ago

I just need some time to implement the new design. Perhaps this weekend if I have time.

untitaker commented 8 years ago

Off-topic: What do you think about this line:

And then the idea of loading/parsing/compiling templates at compile-time comes to mind, but I suspect that the necessary APIs aren't stable yet in Rust, and that it's too late for those kind of major feature requests.

In particular, I dream of a template engine where templates are parsed at compile-time, and are translated into Rust code. That almost certainly would bring speedups, but most importantly we wouldn't have to convert everything to JSON before passing it to a template, since it all boils down to Rust.

Example. This:

fn main() {
    let data = BTreeMap::new();
    data.insert("foo".to_owned(), 42);

    println!("{}", mytemplate(data));
}

handlebars!("mytemplate", "{{ foo }}");

compiles into:

fn main() {
    let data = BTreeMap::new();
    data.insert("foo".to_owned(), 42);

    println!("{}", mytemplate(data));
}

fn mytemplate(data: BTreeMap) -> ... {
    data.get("foo").unwrap()
}

maud has this idea implemented but the template language itself is far too simple for my purposes (handlebars fits well). Also I guess one would have to think about how to implement a template registry with this design.

sunng87 commented 8 years ago

I haven't look into rust's macro system. If it's like lisp languages that has same capabilities at compile-time, it's fully possible to move template parsing to compile-time. Currently a template is consisted with a vector of TemplateElement in memory, it's possible to inline these elements at compile-time.

However, rendering handlebars template involves some dynamics such as template lookup, we may still have to do it at runtime.