[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)