
Universal Jinja: a crazy idea for a Python-ready front end - coffeefirst
https://whatisjasongoldstein.com/writing/universal-jinja/
======
skywhopper
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.

~~~
snissn
What is a "good template language"?

~~~
vosper
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.

~~~
deckar01
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.

~~~
captainmuon
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).

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

~~~
captainmuon
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.

------
sametmax
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](https://github.com/kovidgoyal/dukpy)).
We even have pluggable renderers
([https://pypi.python.org/pypi/PyExecJS](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](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.

~~~
vosper
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

~~~
sametmax
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.

~~~
vosper
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

------
stevebmark
"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.

~~~
twblalock
> 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.

------
zepolen
I've done this many years ago with
[https://github.com/wkral/jinja2js](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](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.

------
bastawhiz
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.

~~~
deckar01
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.

------
Walkman
Mike Bayer wrote a really interesting article about this topic 5 years ago:
[http://techspot.zzzeek.org/category/mako/](http://techspot.zzzeek.org/category/mako/)

These techniques are easier with the Pyramid framework.

------
cyberpanther
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.

~~~
stevebmark
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.

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

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

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

~~~
wbillingsley
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.

~~~
StavrosK
The logic is inescapable.

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

[https://github.com/mozilla/nunjucks/blob/master/CONTRIBUTING...](https://github.com/mozilla/nunjucks/blob/master/CONTRIBUTING.md)

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

------
dochtman
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.

[https://github.com/djc/jasinja](https://github.com/djc/jasinja)

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:

[https://github.com/djc/askama](https://github.com/djc/askama)

------
ivanbakel
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.

~~~
sametmax
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.

------
erlehmann_
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

[http://www.workingsoftware.com.au/page/Your_templating_engin...](http://www.workingsoftware.com.au/page/Your_templating_engine_sucks_and_everything_you_have_ever_written_is_spaghetti_code_yes_you)

~~~
sametmax
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.

~~~
erlehmann_
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?

------
dchuk
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.

~~~
sametmax
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.

~~~
dchuk
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)

~~~
sametmax
Push requires js as well.

~~~
dchuk
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.

------
omegaworks
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.

~~~
jasonthevillain
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.

~~~
andrewingram
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.

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

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

~~~
andrewingram
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.

~~~
mixmastamyk
:D

[https://news.ycombinator.com/item?id=14839576](https://news.ycombinator.com/item?id=14839576)

------
amirouche
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.

~~~
Daishiman
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.

------
pbreit
Has anyone had good experience with turbolinks on python?

------
uptownhr
Try nuxt for vuejs

------
ben_jones
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

~~~
benologist
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.

