Comments (35)
Will be even harder if we pass functions instead of custom templatetags
from tera.
When starting webdev in Rust I thought about having a templating engine that compiles all templates down to normal functions at compiletime. That would solve this issue and also give you compile-time template validation without having to pay the same cost at runtime.
from tera.
And I realize this idea has been brought up many times before, but so far what I am missing from all of them is everything every other templating library provides:
- Templates in separate files
- Bound to the filesystem, so it's easy to include other templates by path relative to basepath
- Blocks
from tera.
The main issue I have with the template -> rust approach is how would it work for use of the library in a self contained way.
For example let's say I make a static website generator like http://gohugo.io/, I want to just use my hugo binary, have some markdown/html files and have the output in the end. If I have to go through a build.rs
compilation, this use-case is not possible afaik?
I'm not sure either how it would generate some of the code and I don't see how to give meaningful error reporting.
Either way that's something that needs an answer before adding more code since I don't think we can retrofit type safety after adding more features
from tera.
One potential solution would be to have 2 renderers: one typesafe (ie need a build.rs) and one not typesafe that can be used without rust.
Downside is that you would be limited to what is possible in the unsafe mode, ie no rust or random function call which isn't a bad thing in itself.
Not sure if that would work but that's the only idea i've got so far to work in both usecase but it seems like it should be almost 2 different libraries.
from tera.
If the type system doesn't suffice, we could add one or more lints to ensure safety.
from tera.
I'd be interested to hear from people that have experiences with codegen in rust if my plan above is sound or whether it should really be 2 different libraries.
from tera.
@untitaker would the plan above be what you had in mind ?
from tera.
I didn't think about static site generators at all, good point. I think you might be able to define the untyped interface in terms of the typed one, where each type is rust_serialize::json::Json
(or serde's equivalent).
You might get away with pretty strong typing even for static site generators, if only the template is dynamically loaded (and not the render context's type).
from tera.
The issue is that type safety would require code generation which would need having rust compiler so loading a template dynamically wouldn't work unless I'm missing something.
from tera.
Maybe Tera doesn't need to support static sites generators, there are enough of those already
@untitaker @llogiq any idea on what would be the best way to generate code? I have some time next week so planning to work on that a bit. The easiest would be a template file using something like mako/handlebars that I fill I think? Seems much easier than dealing with the AST as well
from tera.
If you use a build script, you can check arbitrary files by creating the respective source and compiling with -Z no-trans
. This allows you to embed proofs in the type system that don't need to appear in the final code
from tera.
I don't really see the difference in complexity between a macro accepting a path vs a string literal. rust-peg is an example for a syntax extension that supports both, though it uses Rust Nightly APIs instead of Syntex.
On 22 April 2016 23:31:59 CEST, Vincent Prouillet [email protected] wrote:
Maybe Tera doesn't need to support static sites generators, there are
enough of those already@untitaker @llogiq any idea on what would be the best way to generate
code? I have some time next week so planning to work on that a bit. The
easiest would be a template file using something like mako/handlebars
that I fill I think? Seems much easier than dealing with the AST as
well
You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub:
#24 (comment)
Sent from my Android device with K-9 Mail. Please excuse my brevity.
from tera.
I don't get what you mean @untitaker? Also curious of what @mitsuhiko think of a typesafe template engine.
In my mind, you would have the template like now and it would build a .rs
file containing functions like render_user_profile (for user/profile.html).
The user would have to specify the types of variables in the template though (ie something like {{ types user=&User friends=Vec<User> }}
) so we can build the params for the templates method.
With that in place, we might be able to get rid of serde dependency, but i'm not sure how filters would work without it right now.
from tera.
@Keats Then I am unsure what you mean with:
Seems much easier than dealing with the AST as well
from tera.
Generating the .rs
file by building a rust AST with syntex for example
from tera.
I am writing exactly a static site generator in Rust, and I got interested in Tera because I dislike handlebars syntax, while I like jinja2/twig syntax.
The same problem with not being able to generate templates at compile time can happen in medium-to-large teams, where templating is done by frontenders. This would also exclude theming for any application, be it web or not. For example: imagine I want to package a rust software like they do with Electron and allow the user to download themes.
I don't think it's a good idea to go "fully static compiled". It would cut off a lot of use cases and a lot of people.
The idea of two renderer seems interesting, but poses the problem of objects' methods, that could be resolved in the compiled version but not in the dynamic one. It wouldn't be much of a problem, though, as if I use the template as dynamic, I will know I won't have objects in there, but just strings/numbers/bools and arrays and hashes of them.
In this mode, the "declaration block" would be completely ignored in the dynamic version and enforced in the static one.
Filters could be an interesting problem. A solution could be just leveraging a ToString or a ToFilterArgument trait in the object, transforming everything to string (possibly a JSON string) before passing it to the filter. This would mimic the Unix pipes behaviour and allow the same filter to work for both static and dynamic templates.
In the end the user writing the template will be aware of the differences, and be able to choose what to use based on the project's requirements.
from tera.
Good points.
I'm a bit afraid how complicated it will be to have both typesafe and non-typesafe in the same package though. It would be nice for the end use to be able to use both from the same crate though and the parsing will be almost be the same.
For the object methods, I don't think I would allow it in the typesafe anyway since that would make template logic too complex imo (and my opinion on that can be changed of course).
I think one way to do it would be to have the dynamic templates working and fully featured (currently missing filters and custom fns) and then try to add some codegen on top of that engine.
from tera.
Good comment from yesterday's meetup: instead of having
render_user_profile(title, user, friends, theme, blabla)
we could have
render_user_profile(data: UserProfileData)
where the struct would have been generated for us
from tera.
I thought about the concept of type safe template engines quite a bit. I think one big problem is that a not insignificant reason of why templates are being used is that templates can be user supplied so requiring compilation via rustc seems to be quite inhibitive of this. Unless this can be accomplished without rustc I would recommend just not exploring that area too much.
Object methods turned out to be amazing in Jinja. They allow you to move complexity and logic out of the template code into the application. It might not be completely unreasonable to have methods work in Tera but this might require compiler plugins.
Right now the fact that Tera is limited to JSON is a bit limiting. In particular the problem arrives not being able to differentiate between HTML strings and strings as well as not having a date/time type available.
I feel like this is something that should be explored in detail because categorically rejecting non JSON types and methods will cause problems in the longer term.
from tera.
@mitsuhiko how would you handle data without Json? I'll take any good ideas, i'm currently adding filters and it would be nice to keep the types of the args, which I could do by having a HashMap<String, Json>
but it makes JSON used in the parser as well.
I could do like Serde and have a Value
enum type but I would need to add custom derive to make it on par with Serde, so maybe once macros 1.1 are in.
I came to the same conclusion for typed templates, it's a nice idea but in practice not something I'd need I think.
from tera.
@Keats i'm toying around with a few things. My thinking is that the best course of action will be to have a custom trait with compiler plugin now that this becomes a possibility.
from tera.
@mitsuhiko I came to the same conclusion in #45
For now i implement filters with serde_json
but that should be easy to swap out later on
from tera.
I wonder if it's possible to support methods that way as well in a way.
from tera.
https://github.com/djc/askama is using macros 1.1 to get templates compiled to Rust code
from tera.
I use http://hackage.haskell.org/package/shakespeare in my day to day work and it's quite lovely. In fact, the only thing I don't like about it is that it's HAML-esque instead of plain HTML like Jinja templates.
One of my favorite things about it was the type-safety. Shakespeare has type-safe templates by default, but it is capable of parsing and rendering templates at runtime by reusing the already-extant code that gets executed at compile-time. This is possible in large part because of Template Haskell, I don't know the state of Rust macros well enough to say whether that is possible in Rust or not.
I would urge you to remember that the best of both worlds does in fact exist and has been done before.
from tera.
I'm not against it in principle if you can have both compiled + interpeted but for my own use-cases, I should be able to use templates without Rust/Cargo. That constraint removes many good things a compiled template offer.
Can you run shakespeare templates without having ghc installed? Also how long does templates compilation take on your projects (I'm curious)?
from tera.
Can you run shakespeare templates without having ghc installed?
I'm not certain what this question means. Let me turn it around so you understand, "can you render a Jinja2 template without having Python installed?"
The "best of all worlds" as I understood it was being able to have type-safety at compile-time for templates baked into the app, but also have your app be able to accept arbitrary templates as input for rendering at runtime. This is relatively trivial with Hamlet's TH is lifting ordinary Haskell code into the compile time execution environment.
Template compilation is fast as long as the template is quasi-quoted in a Haskell module, which I usually do. You can have templates in separate files, but then it's a touch slower.
from tera.
I'm not certain what this question means. Let me turn it around so you understand, "can you render a Jinja2 template without having Python installed?"
Jinja2 no, Go templates yes.
Sorry i wasn't clear, let me give you some of my own current usecases for templates engine:
- User defined templates from non-technical users, ie can't ask people to write code in it
- Static-site engine: I want a single binary that can compile/live reload templates without anything specific installed
I don't really write any templates in the backend itself these days, except for extending flask-admin or the django admin.
from tera.
User defined templates from non-technical users, ie can't ask people to write code in it
Static-site engine: I want a single binary that can compile/live reload templates without anything specific installed
Those are both served by runtime rendering of templates. Presumably they'd be using a static site generator written in Rust, or the web app is written in Rust.
from tera.
I'm wondering if there's some miscommunication going on.
Can you create a binary with 0 template in it, give it to someone like me without ghc and let me write templates, have the binary parses all those templates and render them, have 10ms live-reload when I edit them etc?
Shakespeare seems to allow arbitrary Haskell code in its template (according to http://www.yesodweb.com/book/shakespearean-templates#shakespearean-templates_interpolation) so unless it embeds ghc, I don't see how it could possibly read and compile some random templates I'm writing with random data.
I might be missing something though.
Either way, I'm not planning to implement it since I wouldn't really use myself it but if someone wants to try it, I can make anything they need from Tera is available.
from tera.
BTW https://github.com/djc/askama implements type-safe templates, but doesn't support the static site generator usecase.
Shakespeare appears to be compile-time as well. There is no indication that you can compile templates at runtime without linking ghc.
from tera.
@untitaker Askama is pretty close to what you were describing at the beginning of the thread, what are your thoughts on it?
I don't think it would be possible to have a crate working as both interpreted and compiled, since with compiled you end up having to use Rust in the template (https://github.com/djc/askama/blob/master/testing/templates/option.html for example) and Haskell in Hamlet.
from tera.
from tera.
Closing this, that's not going to happen
from tera.
Related Issues (20)
- Excessive memory usage of Tera HOT 3
- linebreaksbr is not safe - add `html_encode` filter? HOT 1
- `default` filter: make the `value` optionnal and add `d` alias HOT 1
- Use of `(` and `)` to specify order of operations. HOT 2
- Weird behavior with duplicate variable names HOT 1
- Removing space between HTML tags HOT 1
- Macro names can have underscores but not hyphens HOT 1
- Macro from another macro HOT 1
- More complete Display implementation for Error HOT 5
- Missing a few git tags? HOT 1
- [Question] Help understanding the `indent` built-in
- How to use in the template has . variables
- Round a number with precision not work as expected! HOT 2
- Strongly recommend adding asynchronous call functionality. HOT 1
- Build problem with 1.20.0 HOT 3
- On Linux, the tera could not be built in my project by dylib
- Is this really the shortest attribute safe get/fetch one-liner HOT 2
- Don't return an error if variable is missing in the context HOT 3
- Reload, but reset on fail
- Template fragments HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from tera.