[HN Gopher] MiniJinja: Learnings from Building a Template Engine...
___________________________________________________________________
MiniJinja: Learnings from Building a Template Engine in Rust
Author : todsacerdoti
Score : 100 points
Date : 2024-08-27 14:02 UTC (8 hours ago)
(HTM) web link (lucumr.pocoo.org)
(TXT) w3m dump (lucumr.pocoo.org)
| infogulch wrote:
| A templating language would be a great case for using an arena
| allocator since objects will only live as long as it takes to
| fulfill the request.
| the_mitsuhiko wrote:
| Yes! I did in fact try this but I was unable to find a good way
| to make the API work.
| infogulch wrote:
| Interesting! I suspect a templating engine that uses arenas
| would be a holy grail for rust web perf, so I'm curious about
| your experience trying to use them. As for making the API
| work, do you mean that the arena API was difficult to use, or
| the object interface you built on top of it was difficult to
| implement in a way that was accessible to template execution?
| the_mitsuhiko wrote:
| It depends a bit on what you want to do. I made one attempt
| where I needed to carry a 'arena lifetime everywhere which
| was really tricky. A second attempt was to tag the Value
| internally with an ever increasing ID of arenas. However
| the latter becomes dangerous very quickly because nothing
| binds them together and you end up with a lot of unsafe
| code and I had no trust in my creation.
| infogulch wrote:
| Yeah that makes sense. Maybe arenas will be viable once
| the working group makes progress on allocators.
| https://github.com/rust-lang/wg-allocators
| HiHelloBolke wrote:
| Thank you for this, I just used this to create a rust based cli
| tool to create j2 yamls. This was motivated because we want to
| not use ansible j2 yaml generation instead to a standalone binary
| for it.
|
| Now it feel like helm but it's j2 and outputs a directory of
| yamls with base and overlays in kustomization way. So they can be
| iverriden in gitops by sre if needed
| brucecrust wrote:
| ha man I hate Jinja. Nothing against this or Rust, just from
| working in Flask I have borderline nightmares. That might say
| more about my team that the framework though.
| 0cf8612b2e1e wrote:
| Could you elaborate? I think it's fine? Although I have always
| subscribed to the "Two Scoops" philosophy and keep my templates
| as stupid as possible. Use a variable, simple conditions, etc.
| Anything more complex should be handled at a higher level.
|
| Go templating on the other hand, that drove me bananas.
| murkt wrote:
| I got used to React components, and after that templates feel
| a bit cumbersome and un-ergonomic in places.
|
| I've been using Django templates since 2006. Jinja was
| designed after Django templates of that era, fixing their
| most glaring problems. Don't remember the exact year when I
| started using Jinja a lot. Maybe 2013.
|
| For example, a pure existence of an {% include %} tag. People
| use it, implicitly passing many arguments to some other
| template. Which makes it very hard to understand and change
| later.
|
| Macros are not that pleasant to use, there are less features
| in macros then in Python functions, and tools support is much
| worse too (static analysis, formatting, etc).
|
| Filters... why do I need to write `value|string` instead of
| `str(value)`?
|
| Etc.
| the_mitsuhiko wrote:
| The benefit of filters is that they don't share the
| namespace with the template context and I would argue are
| more readable.
| murkt wrote:
| Not sharing the same namespace is a benefit, I agree. Not
| a huge one, as I don't name my variables "map", "string"
| and similar anyway. And would not look favorably if any
| of my employees did that.
| bityard wrote:
| Every templating engine has to find a balance between doing
| what you need it to do, and letting you write business logic in
| the template itself. (Hey there, PHP.) That said, it's possible
| to write pathlogical templates in just about anything.
|
| I've used Jinja a lot and always thought that it struck just
| about the right balance.
|
| The docs are also way better than they used to be.
| IshKebab wrote:
| The answer is not to use a templating engine. TSX is the gold
| standard here IMO. Using it with https://fresh.deno.dev/ is
| soooo much nicer than old school templates.
| murkt wrote:
| I've been using Jinja2 for years and years, probably around a
| decade now. I don't remember any other docs?
| the_mitsuhiko wrote:
| Yeah the docs never really changed all that much. They look
| more of less the same for 15 years or so.
|
| https://web.archive.org/web/20110727181325/http://jinja.poc
| o...
| golergka wrote:
| I worked on a project that implemented static type checking for
| dbt projects, which are made of SQL templated with jinja and
| some yaml configs. I'm not sure if I hate it, but it certainly
| was fun.
| snarkyturtle wrote:
| Wait until you have to work in Mustache/Handlebars, you'd love
| Jinja
| pietz wrote:
| https://jinjax.scaletti.dev/ cured my pain.
| singhrac wrote:
| I have the opposite memory :) I remember writing complex
| applications in Flask and it just worked right away, and as our
| performance / complexity grew it kind of kept up because it was
| very modular.
| VWWHFSfQ wrote:
| I wanted to make a cli tool for rendering templates with mini
| jinja and also for users to write their own little library of
| functions/filters etc in Lua using mlua and then be able to use
| those in their templates. Unfortunately didn't work. All kinds of
| issues with mini jinja and mlua interactions when trying to
| add_filter, add_function, etc.
|
| This was awhile ago though. Maybe something changed and I should
| try it again
| the_mitsuhiko wrote:
| You cannot register filters with a non 'static lifetime.
| However it's not super hard to work around. Usually an
| Arc<Mutex> is all you need.
| ctoth wrote:
| > The first thing is that Rust is just not particularly amazing
| at tree structures.
|
| As someone who doesn't write any Rust I'd like to understand this
| more. Is it the ownership model that makes trees weird? Is there
| something you guys do instead? I was working on an R-tree
| yesterday for something and I'm slightly surprised to read this
| but obviously Armin knows what he's talking about :)
| __s wrote:
| it's a pain if you want children to reference their parents
| while their parents reference them
|
| Similarly getting a mutable reference to a leaf while parents
| have references to children is awkward
| giancarlostoro wrote:
| I know just Rust basics, what specifically makes it awkward?
| I'm not a heavy Rust user, so I'm having a hard time
| following, do you have any simple pseudo-Rust code you could
| share? I'm also a basic CRUD app dev by day, hobbyist by
| night.
| BonusPlay wrote:
| I'm not a rust expert by any means, but I believe there's a
| problem with lifetimes. There are many ways to implement
| double-linked lists (think C++ smart pointers), but when
| you try to squeeze performance and use references, then
| it's a fight against borrow checker, which ends with the
| need to use unsafe rust.
|
| smarter sources: https://rust-unofficial.github.io/too-
| many-lists/
| https://softsilverwind.github.io/rust/2019/01/11/Rust-
| Linked...
| oneshtein wrote:
| Borrow checker is just a checker, which ensures that
| programmer doesn't write obviously wrong programs. It's
| obviously wrong to create cyclic references, even in a
| language with garbage collector, such as JavaScript. Why
| you need to fight with _checker_?
| kbolino wrote:
| Regarding the borrow checker, what you say is not
| correct. The borrow checker's rules are stricter than
| absolutely necessary. It is designed to reject all
| invalid programs, but it also rejects some valid
| programs.
| LudwigNagasena wrote:
| Why would it be obviously wrong?
| __s wrote:
| garbage collectors detect cycles. you may be thinking of
| reference counting. CPython includes a gc for cycle
| detection
| oneshtein wrote:
| Some people are trying to use references everywhere
| everytime, instead of (safely wrapped) pointers. It's a
| mental lock.
| SkiFire13 wrote:
| Actually, Rust's rules really wants your data to look like
| trees. Requiring each value to have exactly one owner is not
| really different than requiring each node of tree to have
| exactly one parent.
|
| The problem however comes when you want to reference the parent
| from a child. In the ownership/reference graph that would also
| count as an edge, and hence creates a cycle with the parent-to-
| child edge. There are workarounds like using weak reference
| counted pointers or indexes into arrays, but ultimately they
| don't offer the same ergonomics as other languages and it's
| better to design with only parent-to-child links.
| oneshtein wrote:
| Why you want to create cyclic reference from child to parent
| instead of a bare pointer?
| Cyph0n wrote:
| Because dereferencing a raw pointer in Rust requires
| unsafe.
| pietz wrote:
| I really don't like Jinja. The syntax is not for me and there's
| often three different ways of building the same thing. I find it
| a bit confusing.
|
| Recently I started using JinjaX (https://jinjax.scaletti.dev/),
| which is weirdly amazing. I think the comparison on the homepage
| explains it quite well. It feels like what Jinja always should
| have been and and the multiple ways of doing the same thing
| converge into one syntax in JinjaX.
|
| I really hope the project gains more traction.
| murkt wrote:
| > JinjaX components are simple Jinja templates. You use them as
| if they were HTML tags without having to import them: easy to
| use and easy to read.
|
| ...and impossible to understand and keep track of what goes
| where.
|
| No, thanks. Components are a good idea, and no imports is a
| horrible idea.
| adontz wrote:
| Do I understand JinjaX correctly, that it's specifically for
| HTML templates, not text templates in general?
| pietz wrote:
| Yes
| krick wrote:
| IDK. I always though Jinja is the best templating engine and
| was surprised by your complaints and the Jinja sample on that
| website. What doesn't he like? Looks totally legit...
|
| After reading JinjaX sample, I see the point. I would agree
| that it's much cleaner... If not for the fact he uses
| capitalized tags to distinguish between templates and html. I
| hate it. First off, it just throws me off, I cannot tell at the
| glance anymore where is the real text, and where is templating
| voodoo-magic. How do I find the source files fot layout and
| pagination? Right, I just have to know the convention. Second,
| it's remotely justifiable and can be attributed to a matter of
| getting used to only if it produces html. Templating engines
| are not restricted to html. It could be producing markdown, it
| could be producing XML. If only the author of this library
| restrained himself to be less funky and not introduce any
| ambiguous idioms, it would be pretty perfect. But as it is, I
| don't think I could use it.
| pietz wrote:
| Different tastes, I guess. It's the same syntax that many
| JavaScript Frontend frameworks like react and Svelte use. I
| find it much cleaner.
|
| When using Jinja with HTMX you also run into trouble that it
| doesn't nicely support partials. You could use the
| jinja_partials library but I just find JinjaX so much more
| pleasant.
| the_mitsuhiko wrote:
| For what it's worth MiniJinja lets you render individual
| blocks if you so desire: https://docs.rs/minijinja/latest/m
| inijinja/struct.State.html...
| the_mitsuhiko wrote:
| I don't think that Jinja is the right way to build HTML heavy
| anything. Look at JSX for that. However I do find it
| interesting how this is a constant back and forth.
|
| I remember when the template engine that everybody in Python
| used was kid (precursor to genshi) which was XML based and
| looked a lot like vue/jsx does today. Back in the day people
| did not like it at all because designers found it hard to work
| with.
|
| Now the situation is a bit different but what do I know where
| we land in 10 years. It feels like a constant cycle ;)
| geenat wrote:
| IMHO Jinja was never worth salvaging. It's a bandaid for not
| being able to mix Python and HTML easily.
|
| Super slow parsing. Unintuitive DSL (opinionated enough to be a
| PITA). Huge LoC vs the value it contributes to your project.
|
| Adopt a different system.. see: ERB, PHP, EJS- all of these are
| extremely fast and intuitive (just the native language + an extra
| tag or two).
|
| Edit:
|
| Of course.. this is authored by the jinja guy.
| krick wrote:
| Except no cultured adult programmer would use the original PHP
| syntax for templating, unless it's some 5-minutes worth
| development script. It's too powerful and too complicated.
| People use smarty or twig, which are basically the same thing
| as Jinja.
| lyu07282 wrote:
| I always liked TAL, it kind of made sense to me that the
| templating engine itself understands the syntax of the
| language you are templating. It ought to be impossible to
| write invalid HTML/XML. It's like the pain you get into when
| templating YAML with jinja, but if the YAML template also
| were itself a valid YAML file it would be much cleaner imho.
| the_mitsuhiko wrote:
| I don't disagree but we ended up with systems like Jinja
| because that's what people adopted. I also built GHRML
| which was a syntax aware template engine for generating
| XHTML documents and it never really took off.
|
| Sometimes it's the simple and dumb solutions that win out
| over the cleaner stuff. Nowadays maybe less so, JSX clearly
| won and if you build UIs today that's probably what you
| should go for. However there were many solutions like JSX a
| long time before and somehow the value proposition was not
| right for the software written at the time.
| Jackevansevo wrote:
| To add some balance to everyone slating Jinja in the comments,
| I've personally found it great to use.
|
| Sure you CAN write unmaintainable business logic spaghetti in
| your templates, doesn't mean you SHOULD (Most criticism appears
| to come from this angle).
___________________________________________________________________
(page generated 2024-08-27 23:01 UTC)