13 ms·
Universal Jinja: a crazy idea for a Python-ready front end
- ivanbakel 9y agoThe 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 9y agoIf 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.
- bastawhiz 9y agoI 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 9y agoI 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.
- jasonthevillain 9y agoAgreed, testability is a big problem, I'll add a note. Thanks.
- sametmax 9y agoI 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 9y agoI'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
- RobertoG 9y agoYou 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.
- erlehmann_ 9y agoTemplates 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_engine_sucks_and_everything_you_have_ever_written_is_spaghetti_code_yes_you http://www.workingsoftware.com.au/page/Your_templating_engin...
- sametmax 9y agoThis 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_ 9y agoYes, 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?
- chickenfries 9y ago> 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"
- dchuk 9y agoI'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 9y agoNobody 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 9y agoSo 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)
- brianwawok 9y agoWhy 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.
- omegaworks 9y agoUgh. 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.
- sametmax 9y agoI 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.
- jasonthevillain 9y agoThat'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 9y agoTo 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 9y agoLooks to be an alternative to the traditional "rest api". Would anyone care to comment on the productivity benefits of one or the other?
- andrewingram 9y agoIt'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.
- skywhopper 9y agoUgh, 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 9y agoWhat is a "good template language"?
- vosper 9y agoJSX 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.
- nilved 9y agoFrom that description it sounds nightmarish.
- eropple 9y agoThat "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.)
- krapp 9y ago>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.
- Walkman 9y agoMike 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.
- chickenfries 9y agoWould not recommend using Nunjucks, unless you would like to contribute to maintaining it. https://github.com/mozilla/nunjucks/blob/master/CONTRIBUTING.md https://github.com/mozilla/nunjucks/blob/master/CONTRIBUTING...
- joshmaker 9y agoActually, we've started maintaining Nunjucks at The Atlantic (it's in the references of jasonthevillain article).
- zepolen 9y agoI'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.
- pbreit 9y agoHas anyone had good experience with turbolinks on python?
- ben_jones 9y agoCan 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
- s_kilk 9y agoProbably just the cost of making high-quality ports of Pug in every language.
- benologist 9y agoIt 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.
- InstanceOf 9y agoVuejs can be configured to use pug.
- mixmastamyk 9y agoSo I'm thinking what the heck is pug?, and looked it up. Looks to be "haml with templating" in a single language. Great idea.
- dochtman 9y agoI 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
- cyberpanther 9y agoI 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.
- erikpukinskis 9y ago> 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.
- cyberpanther 9y agoValid 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.
- stevebmark 9y agoIf 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.
- stevebmark 9y ago"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 9y ago> 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.
- uptownhr 9y agoTry nuxt for vuejs
- amirouche 9y agoI 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 9y agoThey 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.