Hacker News new | comments | show | ask | jobs | submit login
Universal Jinja: a crazy idea for a Python-ready front end (whatisjasongoldstein.com)
171 points by jasonthevillain 11 months ago | hide | past | web | favorite | 124 comments

Ugh, Jinja is not an "excellent" templating language. It's a terrible broken mix of pythonisms and arbitrary-feeling restrictions and oddly missing pieces. It becomes hard to read very quickly and some of the looping idioms are just nuts. Sorry I don't have anything constructive to say here but I'm genuinely taken aback that there are apparently big fans of Jinja.

I'd like to hear more about:

  - the broken mix of pythonisms
  - the arbitrary-feeling restrictions
  - the oddly missing pieces
Because I can't find any.

Check this fiasco out for starters:


> It was never documented that you can override variables from higher scopes

But you could, and people did... because that's what people do: they try stuff that seems reasonable and if it works they use it. And then someone "fixed" it in a minor release and things started breaking. BTW the error message is

    KeyError: 'undefined variable: 0'
Fun way to spend an afternoon, I can assure you.

I used Jinja2 happily for years on a web app, but that thing pretty much just styled a page for flash to sit in and drew some forms and menus. I use it now via Ansible and have come to despise it through and through.

The other day I was debugging an Ops issue only to find that it originated in a python-based executable. I soon found out it was a feature unfinished and buggy. There is a github issue that documents it, it has been around for no less than 10 years. 5 people offered PRs that got rejected for style and they are still discussing how to fix the bug in the most pythonist way.

I'll try to find it again. I obviously ditched the

Fastest solution: fork the code and merge the PRs into your own branch yourself.

I like Jinja. What's a Python templating language you prefer to it?

Randomly chiming in here, but now that I've used Hiccup (in Clojure) for a few years, nothing else seems evenly remotely pleasant to use. Especially when it's hooked up to a good IDE for super-easy key bindings (emacs + paredit for me).

Shameful plug, I liked hiccup so much I "ported" it to elixir: https://hex.pm/packages/sneeze

I love hiccup so I wrote http://escherize.com/hiccup.space

Just to note they are equivalents in other languages including Hiccup's grandfather CL-WHO - https://stackoverflow.com/questions/671572/cl-who-like-html-...

Imo jinja2 and Mako are the best template systems for python - both have their own strongpoints.

Also chiming in. I like Jinja and handlebars and mustache and JSX makes me want to puke. I love Ractive but hate React. Recently back on django and have done a bit of django-ractive messing about so yes it is crazy. It'll never work. You get them mixed up in your head and it makes your brain hurt. But maybe this is a better. I give it a go.

Your "x and x and and x" sentence is about hard to parse! I was wondering whether you hated handlebars and mustache also.

stpl, a.k.a. SimpleTemplate. It comes with Bottle, which is the project Flask was inspired by.

From what I've seen of other template languages, it resembles Mako the most, though some of the syntax superficially resembles Jinja2.

I like it too, but for larger projects I think Jinja lets you repeat yourself less.

I like Jinja. It's straightforward, easy to reason about. I'm a bit taken aback that you _aren't_ a big fan.

One of the big failing of Jinja in my opinion is that it's Python with only instance methods, but Python has a weird, arbitrary-seeming historic division between basic functionality being implemented as global functions versus instance methods.

So if you want to replace a character in a string, that's fine, because `replace` is an instance method:

    Changed plus to dot: {{ string.replace('+', '.') }}.
but if you want to take the length of that string, you need a Jinga-specific filter to have been implemented, because getting the length is via a global function `len()` in Python. This fails:

    My string is {{ len(string) }} long.
If you're just using Jinga to build some HTML or whatever and you were always in your own Python code right before the template it's not really a problem, 'cause you can just do it in said Python code. I happily used Jinga for several web apps for years.

I really started to hate it in Ansible though, where I'm often just trying to get a one-off little operation done that I would rather have obvious right there in the template source rather than having to bounce over to a one-off filter function (or invoke some other outside code), and I can do it in Jinja, but it just looks and feels like hell... which kinda defeats the purpose.

I feel like Jinja was an especially bad fit for Ansible, but as a templating language I feel like it's main strength is it's better than D'jango templates... but that doesn't matter much outside the D'Jango world.

As a logic-ful template language I think it's deficient because it omits the functional parts of Python, which - as discussed above regarding `len()` - are very core to Python, and Jinja adds them back in a different way that requires extra mental overhead to keep track of. I really like the pipes (filters) but it would have been nice to just keep the Python globals as well for consistency.

And if you really want to go logic-less with your templates, I think Mustache(-variants) would be the way to go since they're much more truly "logic-less" and they're supported across a plethora of different runtimes besides Python, giving your much more flexibility. I've never really had the patience / discipline / right use case for logic-less though, so I'm far from an expert in this area.

Jinja is just a really weird mix... it's not logic-less, but it's not Python... it's a funky half-logic mishmash. It obviously makes sense and feels right to the people that make it, and if it makes sense and feels right for you that's awesome, but I hope you can understand how could feel awkward to others.

What is a "good template language"?

Pug templates(https://pugjs.org/api/getting-started.html) are fairly nice.

The main dlang web framework, vibe.d, uses a 1:1 copy called "diet" templates (You can insert D code to be run on the server, with the arguments given to the HTTP request/response). This works very well IMO, mainly because D is a very good programming language, so you can mix very fast / expressive D code with your regular JS for client side work.

Oh god, no. I don't know if I'm missing something but pug has been single handedly the worst templating engine I've ever seen. Why would you want to write some cryptic template that somehow gets turned into HTML?

For me, forcing me to be good about whitespace is very nice, no closing tags is even better, but the real kicker is


    <div class="sep"></div>
So short and concise! And the "somehow" isn't that magical... The code you right else where ultimately gets transformed into something else, too!

Typed that mobile and wish I could edit it... Sorry!

Similarly Nim templates (they are called filters in Nim) are very good. It's just Nim code with markup code interspersed, it works very well but I do admit that it could still be improved.

What I like most about it is that i can just use Nim code in my templates. I can't say the same for Django templates or (I guess) Jinja.


I'm a huge fan of Pug. Out of the various view engines I've used, it's been the most intuitive and productive for me. Pug, with it's indentation defined blocks, seems like a good fit for Python (less context-switching), though I've mainly used it with Node.js.

One peeve: managing multiple partials for a single page with mixins seems a little more complicated than necessary.

JSX is kinda nice, once you get used to it. Primarily because it's just HTML and/or your custom components, with arbitrary code execution in { } blocks.

When I see JSX in a project I can't help but notice how similar it is to PHP pages that inline all the applications logic with the template making it unreadable. When it comes to react I think JSX is even worse than PHP when javascript objects are passed in and out of JSX directives. It is so hard to debug, and a nightmare to read.

That is true, but it is somewhat alleviated by the fact that react restricts what you can (or should) do in a component. A good component has one-way data flow and behaves like a pure function (modulo some AJAX, or interfacing with non-React code, but you can isolate that pretty nicely). Yes, it is not enforces, and JSX can be a footgun. Also, the separation of concerns is along a different line (not markup / behavior / style, but between components. If you want to "theme" your website, its kind of hard). I'm not a diehard functional fan, but I find if you go with it it can actually be pretty maintainable and clean. Tooling is also very good, especially with TypeScript (TSX).

TSX has kinda driven me nuts because react-redux connect doesn't seem to type cleanly. Has that improved?

I haven't tried redux with tyepscript yet. One thing that doesn't seem to be typed correctly is immutability-helpers (it catches some errors, but some stuff seems to be `any`).

It is impressive though how often you have types when I wouldn't expect it.

This is why the React Inspector exists, and it's very very good at what it does.

It's really not that, and I think the general perception that it is causes a lot of people to look at it with suspicion or reject it outright.

JSX is a data structure with a syntax similar to XML. The angle brackets are quite similar to brackets around any other data structural literal in any other syntax.

The tag names are references to either in-scope variables/constants (when capitalized), or references to a static set of HTML element names specified by React (when lowercase). This is different from HTML or even XML because they are evaluated at runtime (plain JSX->JS compilation) or validated at compile time (e.g. TypeScript).

The attributes names are keys in the data structure's props, and the values are either static (if specified as string literals) or dynamic (if specified between curly braces). These too can be checked at runtime (with PropTypes) or at compile time (e.g. TypeScript).

By specifying dynamic props (or conditional children), the component will re-render as the values change.

I'm not aware of any other HTML-like or XML-like template language which functions the same way.

Edit: I forgot to mention, dynamic props are also exactly JavaScript/JSX expressions. Basically JSX is a macro that turns the XML-like stuff into React API calls.

Apples and oranges. (Or fruits and oranges?) JSX can only do XML; Jinja is for arbitrary text.

Not quite true. Just because JSX resembles XML, it doesn't mean it can only output XML. Plenty of non-XML render targets exist for React: canvas, terminal, Sketch (I believe the file format is JSON).

The primary restriction is that your output can be modelled as a tree in some way, and what you find is that nearly everything falls into this category. I don't know if anyone's done it yet, but a plain-text renderer is certainly possible, I imagine it would be very similar to a terminal renderer.

If you're saying that JSX can do more than XML because you can transform from XML into other things, then yes, that's trivially true.

No, I'm saying that JSX isn't XML, it just very loosely resembles it. It can't even naively output XML because it (currently) mandates a single root node, and XML has a doctype node as a sibling to that.

JSX transpiles down to a tree of function calls, it's literally nothing more than that, the only time it might be considered XML is in the final rendered content. Syntactically, JSX isn't even valid XML.

From that description it sounds nightmarish.

That "arbitrary code execution" is functional viewmodel stuff. It makes complete sense once you've spent more than an hour with it.

(This is also why "templating languages" in PHP were a special kind of foolish; PHP is a templating language.)

>This is also why "templating languages" in PHP were a special kind of foolish; PHP is a templating language.

Any PHP project of any reasonable complexity will either use an existing "templating language" (by which you probably mean a framework) or be forced to create some sloppy, ad-hoc version of one, because while yes, PHP is a templating language/framework, it's also a terrible one.

In my time with PHP, I never found a PHP templating language better or more effective than using PHP itself. At the time, the big ones were Smarty and Twig; both are stump-dumb tools designed to make easy things annoying and hard things impossible.

Emitting HTML is no different from any other functional programming task. State in, HTML out. (You had to be a little clever because you had to ob_start/ob_get_buffers/ob_end, but whatever. Still better than the alternatives.)

>both are stump-dumb tools designed to make easy things annoying and hard things impossible.

What hard things, specifically? I've used Twig a lot and never found it to get in the way of anything else I was trying to do.

>You had to be a little clever because you had to ob_start/ob_get_buffers/ob_end, but whatever.

By the time you have some general abstraction to push "state" into and get "HTML" out of, and deal with output buffering, header management, etc, you've started building an ad-hoc framework.

It's been a while, but I found Twig (and most mustachealikes) just super confining. I don't want to go write a function to transform my state and then expose it to Twig, I want to write a function. (They are pure functions, of course, because...well, competence, y'know?) Just stuff like that. It all gets built to PHP, but with limiters I don't need and (IME) teams that understand functional (in the pure-function sense, not the typeclasses-and-shitting-on-people-who-don't-write-Haskell sense) programming don't either.

> By the time you have some general abstraction

Sure. It's about a dozen lines long. And the language is the actual language I'm working with, not something that needs its own parser to give me less functionality in the spirit of mollyguarding on behalf of people who make mistakes of classes I categorically refuse to allow in my systems. (Please don't mistake this as me saying "I don't write bugs." I write many, many bugs. But I structure programs such that some bugs are very, very hard not to make obvious and to avoid.)

For similar reasons, this is why almost all of my web stuff these days uses a Node backend and a React/JSX or React Native frontend. Consistency across the whole thing, buttressed by tools that encourage good practice without chopping you off at the knees.

>And the language is the actual language I'm working with, not something that needs its own parser to give me less functionality in the spirit of mollyguarding on behalf of people who make mistakes of classes I categorically refuse to allow in my systems.

Ok. But to be fair, Twig's parser is extensible, whereas PHP's isn't. And it lets you use array shorthand in PHP versions that don't support it (which is not as much of a problem as it used to be, but to me, more than worth never having to type "Array()" again.)

Have you tried the XHP functionality in Hack? It treats XML as objects and understands it in context (which is something PHP should do natively, but can't.) It seems to solve many of the footgun problems that PHP template languages do, within native code.

XHP is after my time with PHP, so no, but that's a fine way to handle that to me. (And it reminds me, too, of JSX, which I really like.)

I'd argue that it's better to use a markup-generating DSL than a templating language to begin with. Then you simply get to use native language constructs to accomplish your goals and take advantage of the natural lexical scope of your view code to inject data into your markup. Plus, it lends itself to generating an intermediate representation, which is what enables things like virtual Dom.

I actually like Mustache/Handlebars for the sake of separation of concerns, but we're using it primarily for small simple templates for email notifications and confirmation screens and the like and not full-page stuff.

It's another tech that renders just as well on the client as the server.

Jinja is great. I'm also a fan of Play's Twirl.

I like EJS, because it looks as much like normal JS as possible.


Oh, I know exactly what you're talking about. I've seen Jinja code that assumes "Jinja has this feature, so I should use it."

I'm not sure that's the template language's fault and more than Python is responsible for Python code that goes metaclass happy for no reason.

I agree. So far, my favorite templating language is stpl, which comes with Bottle.

The templates used in web2py felt good. Dont know what happened to web2py?

web2py let arbitrary code be called by the client, and its failsafes were full of holes. So it fell out of favour.

That's just nonsense - source?

Handful of open CVEs in Debian. [0]

The brute-forceable admin happened around the time web2py and Django devs started having a few arguments online, like this one [1], which didn't exactly paint web2py in a good light.

[0] https://security-tracker.debian.org/tracker/source-package/w...

[1] https://www.quora.com/Is-web2py-a-good-Python-web-framework

I was wondering if we should not code a Python renderer for one JS framework and be done with it.

We already have one JS engine in Python (https://github.com/kovidgoyal/dukpy). We even have pluggable renderers (https://pypi.python.org/pypi/PyExecJS). Later we will have webassembly renderers in Python, so you will be able to take frontend frameworks, compile them and execute them in Python.

Finally, we have some fantastic framework that are powerful, yet not that big, such as Vue.js, that already have a pluggable architecture for rendering without a DOM on the server side (https://ssr.vuejs.org/en/basic.html)

The Python community has done much more complicated projects already, and half the work is there, so my guess the reason it hasn't happened yet is we REALLY hate js and most of us just touch it to get the job done and go to the next task.

It's a bit like the async situation. We have the tools, but there is no Django of the asyncio because we love our tools as their are so much. I'm so guilty of this.

The problem is: the rest of the Web is moving ahead, and while it's still relevant to do DRF + Vue.JS right now, one day stuff like meteorjs will be so crazy yet stable it will be hard to compete.

I was hopping webassembly would let us eventually run Python on the client side. But I doubt it will happen. However, I'm thinking more and more than it will allow JS tooling to be plugged in many other languages on the server side.

I actually took a stab at this for a now out-of-favor JS framework, Knockout.js.

You can see the project here: https://github.com/Miserlou/django-knockout-modeler

It allows you to take a single Django QuerySet and turn it into a SPA with in-page listing, sorting, filtering with a single Django template tag:

{{ my_query_set|knockout }}

I used in production in a few projects and was very happy. If I were to do this again, I'd re-do it for Vue.js and make the data-syncing bi-directional. But I hope we see more stuff like this.

Cool. Does that parse JS in Python or generate JS from python ?

Generates JavaScript from Django QuerySets in a single template tag.

I've just got back into the Javascript world after several years of Python programming. My gut feeling is that we will end up with APIs in some language, and universal [0] Javascript apps that can render both client and server side. I don't think there's a place for non-Javascript server-side templating in the long run. JS (as a language, forgetting about the frameworks) has really come a long way in the last few years, to the point where I don't think you'll be able to justify having two different HTML rendering systems for much longer.

[0] aka isomorphic, but universal seems to be the new (IMO better, less overloaded) term for that

I don't know, I put Vanilla, jQuery, Angular, React and Vue in production. I used gulp and webpack and manual setup. I used node and static js.

In in end, nothing is well integrated.

You would think the whole bloody "one language to rule them all" concept would make the JS stack the most integrated one of all.

Well to my surprise, far from it. It's a mess of hundred of moving unstable badly documented always changing components that your job is to make work together.

There is no django of the JS word. None.

And because of that, most JS projects I worked on were disposable projects, prototype in production.

Now there is no meteor in the Python word neither. But professionally, I need something solid, not an ongoing experiment.

You can make fantastic stuff with JS, but only because the platform is fantastic. The web is genius. The JS ecosystem is terrible.

But wish, I really wish the JS community would pick on the seriousness of other communities and the python one would take more risks and innovations like the JS one.

Oh, yeah, it's a mess right now. Debugging especially sucks. I'm hoping that given 5 more years of work on server-side JS we'll get to something that's not miserable, and that transpiling will be a thing of the past

You are, my friend, an optimist.

After learn and forget a few js frameworks, see develop the "compile to javascript" fashion, javascript jumping to the server, the different flavours of MVC, "isomorphic programming", subsets of javascript that compile to whatever and etc..; my gut feeling is that it will never end.

If that is a good or bad thing is left as an exercise for the reader.

Or, the other way around:

Write a react clone in Python (complete with "pyx" files), and then use one of the python to js transpilers to compile to js on the frontend. On the backend, you'd use "react" just as another simple template language, whereas on the frontend, you'd also have the reconcilation algorithm.

You will never get a perfect Python on JS, only a mockery of it. It would be more confusing than anything. Beside, transpilers add tons of complexity, and this complexity increase more when the language is very different from JS.

You have things like IronPython or MicroPython, which are different from cPython but good enough.

When I say transpiler, I don't mean just mapping one syntax to another. I mean either really compiling to JS, or having a python bytecode interpreter in JS. It is possible to compile very different languages to JS, for example Nim.

I think it should be possible to support 100% of the core language - even metaclasses, why should that feature be more difficult? Of course you would not map Python classes to JS classes! You would map Python classes to something else, like opaque JS objects.

It is not realistic to support 100% of the library, but that is not neccessary - on the frontend, you wouldn't need to use most libraries, and you don't need C FFI. Most of the time, you'll be only pushing JSON or python objects into templates.

Aren't ES6+ more like Python (or Coffeescript) now than ever? But yes, complexity.

More yes, they have catched up on syntax. But they are far, far away in term of features. Even if we completly discard the huge and fantastic python stdlib (but really, no hashing or uuid in web language ?), Python has still:

- operator overriding

- look up interception API

- metaclasses

- embdedded design patterns: iterator, singleton, context manager, etc.

- multiple inheritance

- standardised imports, with hooks

- controlled gc

- dict comprehension

- generator expressions

- type hints

- string formatting language and operations

- much more comfortable lists

- rich built ins (all, any, enumerate, zip...)

- no weird implicit type casting and comparison rules

- stack traces and very explicit error messages

- support of a lot of charsets out of the box

- multiple notations for text and numbers

- types for bytes

- support for imaginary numbers

And so much more.

Because Python is such an easy language to use, it's easy to think it's just a simple scripting language.

It's not.

It is very, very powerful.

But it has such a smooth learning curve and you can be productive in it so quickly a lot of people never need to see it.

You can compare Ruby to Python. Or Go.

But JS ? It's not even on the same planet. The only reason this abomination has this success is because it has an accidental monopoly on the most awesome and popular platform of the human race: the web.

Nice work, thanks.

- operator overriding - look up interception API - metaclasses - embdedded design patterns: iterator, singleton, context manager, etc. - multiple inheritance - standardised imports, with hooks - controlled gc

One of the best things about JS is that is has none of these features. Smaller languages are better, and blindly adding features is not the way to improve a language.

Unfortunately, nothing in JS can ever really go away, so it's starting to leave the "small language" sweet spot.

JS is better than Ruby by being smaller and infinitely better specified. Go is a nicer language due to being designed from scratch recently by people with excellent taste.

> Smaller languages are better,

In your opinion. There are entire platforms, with literally millions of programmers, which say otherwise - like .NET or C++ for example.

My opinion? There's no point in calling a language better without qualifying a context or use-case. There are so many languages, with so many different (takes on) features, that it's frequently impossible to even meaningfully compare them. Much less to say which is better.

In other words, I can agree with your statement, that "smaller languages are better", for example in fitting your tastes or in ease of implementation. I won't agree that smaller languages are "better" universally, however, because it's trivial to show the contrary. It's enough to point to all the "transpilers", template- or macro-systems that are being written all the time, nearly always for small languages. If smaller is universally better, then how come so many people want more features and are willing to invest their time to write a transpiler?

Personally, I like small, elegant languages - but I also like the big, pragmatic languages, the weird and experimental languages, the special-purpose and exotic languages and so on. Each has its uses and may be a good tool in the hands of a professional.

The most popular projects in js are transpilers and small tooling to do basic operations (leftpad, lodash, etc). Apparently the entire js community is disatisfied with what js comes with.

Why not just something like this? https://transcrypt.org/

It's Python to JS in a way that makes sense to me at least. JavaScript and Python have a lot of similarities in the languages imo especially around classes and functions

Because it's a joke. It's just not Python. Not half of the Python libs work on those things. You don't have serious introspection, most of the stdlib is missing, the stack trace doesn't work as expected, you can forget about async / await and yield from, etc.

To run Python in the browser correctly, you need the entire 3Mo Python VM. Transpiling is not enough because Python semantics are complicated as it is very, very rich.

Comparatively, js is incredibly basic.

"Isomorphic" templates are not enough. You also need isomorphic data fetching for client code. If you have to manually reinvent the same data fetching on the client and server, you don't get the full benefits of isomorphic code. You only have brittle templates with two different ways to glue data to view.

So far isomorphic Node + React has been the best (but not perfect) way I've seen to do this. You abstract out the API layer, and now you can define components and their data sources that have the exact same code on the client and server, and it just works. Apollo/GraphQL is probably a giant leap forward in this as well.

Having an option to do hand-glued "isomorphic" data in a few places is probably nicer than Javascript spaghetti on the front end, but it doesn't get you all the way there. Rails has the same problem by the way, the "Rails way" is coffeescript glue to get any kind of modern front end application functionality. Even with React on Rails you have to have to reinvent data fetching, and lose the benefit of a well structured isomorphic codebase.

Until browsers support a different language natively other than Javascript (which will never happen), Node + React is currently the most straightforward path to get there.

> Until browsers support a different language natively other than Javascript (which will never happen), Node + React is currently the most straightforward path to get there.

I think WebAssembly is promising for this. You could write your app in any language you want, as long as it compiles to WebAssembly.

I've done this many years ago with https://github.com/wkral/jinja2js

It works - but there are gotchas:

1. You can't depend on useful pythonisms/javascriptisms such as

  {{thing or ""}} vs {{thing || ""}
2. Template filter code still has to be duplicated in both languages - i18n such as {{_('String')}} for example - which sort of makes sense - but then you have to do the same for some other, really trivial, filters.

3. Testing becomes annoying because a template can work in one, and not the other - you have to test both.

4. You don't get the newer html diff style virtual dom rendering which can cause issues with stuff like select boxes. You end up with special case code to handle that, which is more of a hassle.

The conclusions from it all were:

a) You do save time over doing it once in python, once in js

b) You don't save time over doing it all in js - especially if you use a newer functional style js template framework (react/vue/polymer)

c) You can still get the best of both worlds by hooking up your templates in js to be rendered by your backend - eg like https://github.com/reactjs/react-rails does.

In the end for my next project I decided to do an api for the backend in python and the website/frontend in react with SSR, and am really thrilled with the results - very maintainable, testable and simple overall.

I see a few problems.

The biggest problem is testability. Testing that a template renders correctly means parsing the markup into a DOM and asserting that certain conditions are met. This is exacerbated by the differences between Jinja and Nunjucks, which can be non-trivial and unexpected (e.g., Jinja will render synchronously, while Nunjucks can render asynchronously--weird async behavior may appear). Since your application doesn't have the same entry point to the code (they're in two different languages!), you really need to write two different sets of tests for the same template to get proper coverage. Templates being templates, you also don't get the granular testability of a React component out-of-the-box, which can be pulled out and tested individually.

Templates alone also don't include anything in the way of handling events, component lifecycle, and other things that make your code actually do stuff. You'll need to bind event listeners manually, and those will of course need their own separate tests.

Making Jinja useful also usually involves adding your own plugins and filters. This happens in Python, which means you'll need to write all of those a second time in JavaScript, and test them. Doing this right means comparing the output of the two versions, which isn't necessarily straightforward. Given the complexity of this, I wouldn't bet money that other engineers would go through the hassle of making sure this is done correctly.

I'd encourage the author to write more about the pitfalls of this approach. It's easy to write {{ foo.strip() }} in Jinja and forget that Nunjucks requires {{ foo.trim() }}, or empty arrays being falsey in Jinja and truthy in Nunjucks.

I recently investigated a jinja renderer for client side templates. Feature support was the main blocker, but I also wanted to do things for the back end templates that don't make sense on the client side.

I setup an asset macro so that I could declare static asset dependencies in my templates at the component level and have them injected into the footer of the page automatically.

Adding a few lines of jinja middleware to my test server made it possible to unit test my templates directly. It also made my HTML fixtures much more enjoyable to write, because I had jinja at my disposal.

I'm glad I didn't limit myself to the overlap of the 2 rendering engines. I am now in a place where I can easily migrate to Vue and start killing off my jQuery dependencies.

Agreed, testability is a big problem, I'll add a note. Thanks.

Mike Bayer wrote a really interesting article about this topic 5 years ago: http://techspot.zzzeek.org/category/mako/

These techniques are easier with the Pyramid framework.

I usually ignore server side rendering or isomorphic rendering. I'm not saying all projects should ignore it but you're really talking about a high level of optimization if you need it. And if you're reaching that level of optimization you probably shouldn't use Python.

Server side rendering only makes the first view faster. After that, everything is rendered on the client and faster that way. And if you use caching with progressive web apps or just file caching in general, the first view will be fast after. So you're only optimizing for the first of the first. You can then provide the initial data in the page request so that saves a round trip on the first request while still rendering on the frontend.

I say all this to just point out that there are many ways to speed up your frontend without doing SSR and they are much easier to implement with Python. So I'd rather exhaust all these techniques before implementing SSR. If I get to that point though, I suspect Python might be the slowest part of your stack. And lastly if you are doing SSR for SEO purposes then just use a prebuilt prerender service.

With all that said if there was an easier way to SSR with Python/Django, I'd definitely use it. But Jinja on the frontend doesn't sound like that answer.

If you're writing a SPA, server side rendering is probably the most important optimization you can make to speed up your application. No other optimization will come close to the benefits of server rendering. SPAs are both slow and perceived as slow. True SPAs are only appropriate for a subset of the web where you have very specific user constraints.

in my experience, a lot of SPA-like pages are slow because their authors didn't think to async-load code that they don't immediately need. When we async load the larger not-immediately-needed components, the page gets faster. Optimizing the data fetching is also important but the simple ways to support server rendering are to eliminate ajax calls for initial data fetching, which is often an improvement anyway.

> No other optimization will come close to the benefits of server rendering.

"Only the Sith deal in absolutes", Obi-Wan Kenobi

Mathematicians also deal in absolutes! Not just the abs function, also proofs and counterexamples.

I have a bad feeling about this...

  ObiWan:   deals_in_absolutes ==> Sith  
  rhapsOdy: mathematician ==> deals_in_absolutes
  therefore ...
We may have to wrap this in spoiler tags for Episode 9.

The logic is inescapable.

I may be wrong, but GMail doesn't seem to do SSR, you have that progress bar when it loads up, so is not really an essential prerequisite as you make it out to be.

I agree that server side rendering of gmail would greatly speed up the load and remove the need for a progress bar. The word on the street is Gmail has too much legacy code in it to much modernizing with. It's also one of the few very special apps that users tend to keep open forever in a tab, and never do page navigation. Definitely don't use GMail as your benchmark unless you're making something as specialized and popular as what they have now.

> Server side rendering only makes the first view faster.

The first view is the most important view, and making it faster is often the most beneficial thing you could do for engagement.

Valid point. In addition to technical optimizations besides SSR, you can make perceived improvements too. If you get a first initial paint in one second lets says, you're not going to hurt engagement. There are plenty of tricks you can pull out first before you need SSR.

Sure if you're using Node.js pull out SSR first since its easier. But for Python right now, it's not the easiest thing.

Would not recommend using Nunjucks, unless you would like to contribute to maintaining it.


Actually, we've started maintaining Nunjucks at The Atlantic (it's in the references of jasonthevillain article).

I actually wrote a JavaScript code generator for Jinja, which allows you to use the Jinja parser and AST and generate pretty readable and fairly sane JavaScript code (for a pretty large subset of full Jinja). I actually used this in my startup (now long dead) where we were able to reuse quite a lot of template code both on the server and the client.


This is in some (conceptual/experiential) ways a precursor to my recent attempt to create a Rusty Jinja-like, which tries hard to take the best ideas from Jinja and mash it up with the best ideas from Rust:


The post reads somewhat rambly, which I suppose is unavoidable if you're doing a quick whistle-stop of a bunch of related technologies showcasing a new idea.

The only thing that doesn't seem clear is why you'd need to combine server- and client-side rendering in a single instance. Jinja is an incredibly useful and well-made tool, and my experience of it with Flask always leaves me with the best impressions of it being exactly what quick webdev should be, but why would you combine it with JS? Surely the use cases are so different that a separate JS library would be just as applicable, and perhaps more fit for purpose.

If you do JS heavy websites, such as ones that require real time data updates, your pages can only render fully with JS. But on the other hand, you may want to pre-render pages on first hit for performance reasons.

Templates cause bugs. The solitary appropriate solution is an unparser – a component that walks an AST and serializes it.

Making sure the result conforms to the grammar of the output language without any unparser would always involve a parser.

> As soon as I'm looking at more than one programming or markup language in the same file, I'm looking at spaghetti code.

Iain Dooley, December 2011


This article has some good points but the reasons we add more logic to templates are:

- just pre-generating everything outside of the template can be very efficients. Especially if you language can't make everything lazy or if you have several representations for the same dataset.

- designers want a bit more freedom that just printing x. Having to go back to the dev team everytime you need a little tweak is terrible

- all templates are not HTML

- it's way easier and faster to prototype

- rendering caching != data caching

- everything is not about display. Linking and injecting resources are a big deal, and putting that outside of the template is a huge pain.

- conditional template inheritance ? includes in loop ?

- stuff like wordpress have entire business based on the fact you can switch templates on the fly without touching the blog code base or without the wp team to know what you are going to need inside the template in advance.

Yes, all of those are reasons. None of those reasons apply if users wwant something understandable, maintainable and secure.

Separation of concerns is a thing that can help designers, no?

> you simply include everything in the markup that might need to be there, and the programmer removes whatever is not necessary

I realize you may not be cosigning on everything in the article you're quoting, but this is the author's first suggestion to an alternative to template languages.

I work on an SPA that was built like this. The index.html is over 10k lines long. It contains almost every single piece of the UI. Templating libraries and languages aren't perfect but they offer a better separation of concerns than just "dump it all in one file and write some imperative dom fiddling code to add different states"

Note that I made a different proposal above the quote.

I think SPAs are either fundamentally dishonest engineering, in the same way that a microwave wrapped in artificial wood veneer is (and a stainless steel microwave is not) or should result in such a template. If you really think that this is too much, IMO you should not make an SPA in the first place.

> I think SPAs are either fundamentally dishonest engineering, in the same way that a microwave wrapped in artificial wood veneer is (and a stainless steel microwave is not) or should result in such a template.

Could you rephrase or expound on this metaphor? I have no idea what you mean by "fundamentally dishonest engineering" or what that has to do with SPAs and templates.

I've been working on a site recently, in Rails, and just been using Turbolinks and SJR (Server Javascript Responses). Granted, it's a content heavy site with fairly light ajax interactions, but it's a pretty delightful process.

So many people jump to heavy JS libs/frameworks to do stuff that can be solved in much more boring/simple ways most of the time. You don't need React/Angular/Vue to submit a form over ajax.

Nobody said that. We just said "if your side IS js heavy, then rendering on the server would be nice".

Not all sites need a lot of JS. But your tweeter clone is going to be very boring if you have to hit F5 every 30 seconds and polling doesn't really scale.

So use push rather than polling?

My point is that many sites don't really need to be as js heavy as they end up, and people end up solving the wrong problem (how to render all this js server side rather than how to reduce all this js in the first place)

Push requires js as well.

I'm not saying don't use JavaScript, I'm saying don't abuse it and then try to dig yourself out of that hole with server rendering. Use the tools you have to the fullest extent that do the job perfectly well before reaching for other ones.

Why don't you think polling scales? I would argue the exact opposite that polling scales great. To a public api can you cache to your hearts delight. To a private api you can shard away.

Also a good point. Polling is also a very straightforward and reliable system, and can be very efficiently with both caching and returning empty responses when nothing has changed, etc

Ugh. After living in frontend land (native mobile and react) I'm really not looking forward to going back to Django.

It feels so irrelevant in the world of backend-as-a-service and GraphQL.

...Please forgive my cynicism. I am looking for a reason to like this. Maybe I should just move on.

I had the opposite experience. Every time I see a JS project trying to do a bit of custom registration and some serious DB design, it's such a pain. The JS stack is great for pretty stuff, but the basics require so much boiler plate.

That's fair.

What got me thinking about these ideas were cases where having a distributed frontend felt overengineered. If you have problems where GraphQL makes sense, this would be a step in the wrong direction.

To be honest, I'd use GraphQL at any scale. I've recently used it in programming challenges for job interviews, and I've used it in production for about 18 months. It's such a good conceptual fit for front-end, that it now feels strange to work any other way.

Looks to be an alternative to the traditional "rest api".

Would anyone care to comment on the productivity benefits of one or the other?

It's more like an enhancement of the traditional backend-for-frontend (BFFs) pattern, enabling ad-hoc endpoints (based on queries) rather than static ones.

The main productivity benefit comes from the fact that the query language is a very good fit for the component model. Each component can declare its data dependencies in the form of query fragments, and these get composed into a single query for the entire UI. It means every time you use a component, you can be sure that you'll have the data you need.

I should add that none of this is a unique capability of GraphQL, I know people who've built similar component-data binding with JSON-API, but it's the full package that's compelling. The query language is lovely to work with. You can build GraphQL schemas around the needs of clients, allowing you to hide any weird data modelling or service boundaries you may have in your platform. As an API designer, as well as a front-end developer, I love it.

I don't understand people still using Django for their web based stuff. I was under the impression that ReactJS + aiohttp was state of the art. Please explain why I am wrong.

They have literally no point in comparison. Django deals with data, business models, form validation, messaging, and backend. You can render to templates or you can use it to host an API server, or whatever you desire.

React does literally none of those things. aiohttp is just a barebones http server with no built-in functionality.

Has anyone had good experience with turbolinks on python?

Try nuxt for vuejs

Can someone explain to me why we haven't normalized html templating with a Pug-like syntax (formally Jade)?

My perceived benefits of Pug/Jade:

* Significantly fewer LOC

* Improved Readability

* A lot of existing tooling thanks to its popularity in the NodeJS community

It seems to me like headless browsing (now in Node) will make it pretty easy to construct your page using the DOM directly on the server without scattered logic and DSLs.

Probably just the cost of making high-quality ports of Pug in every language.

So I'm thinking what the heck is pug?, and looked it up.

Looks to be "haml with templating" in a single language. Great idea.

Vuejs can be configured to use pug.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact