We are using Django "Legacy" Apps.I am puzzled by the "new" Single Page Applications (SPAs). They require extensive routing, authentication, and GraphQL integration, all of which are already handled by Django's ORM and views.Additionally, Django efficiently manages forms. The primary advantage I see in SPAs is enhanced reactivity, which certainly improves user experience. However, HTMX seems sufficient in this aspect.What would be your sales pitch to someone like me?
Twice as much code for the same functionality. They are better if you have a heavily interactive frontend. But th majority of apps don't need that. Github uses a traditional server side renderrd app, if I am not mistaken, and no on has complained about that.
Broadly, if you're happy with Django and haven't felt the need to transition to SPA, power to you. This is the case in some industries. It's generally not the case in b2c, though, and if you haven't felt the pain yet then you likely aren't in touch enough with your customers (or you haven't connected the dots).
I don't need to sell you on the concept though I will address your comment in depth.
In general, React (especially with typescript) provides a far better developer experience than Django+Templates. The latter is extremely brittle, difficult to test, difficult to refactor, difficult to organize. The former is robust, typed, testable, easily refactored. It's simply quicker to work with React. And this has quadratic effects on how quickly work gets done: The whole stack is easier to work with, which has gains on every level such as learning pace, testing, including third party libraries, deploying, finding and fixing bugs, ...
The advantages of an SPA are an extension of this. You get to move more logic in this frontend layer. Routing at the frontend layer is mainly a performance thing: You don't get to re-download and re-render your entire page when going from, say, viewing "Produc 1" to viewing "Product 2". The whole structure is the same but the content changes = you should only get to update the content, right? If you handle routing at the frontend level, this is something you can achieve.
But routing in frontend also enables some new things you just cannot easily do without it. For example now it's trendy to have apps that open content (such as a post) which opens in a preview window/drawer (saving your current state), but if you reload the page or share the url, it loads in its own individual view. Why is it trending now? Because SPAs have enabled that behaviour.
GraphQL integration is definitely not something that is required, and in fact in ~30 client projects of this type, I've only ever done it twice, for two people it was actually relevant for.
But: You generally want an API anyway. Writing your frontend<>backend communication as an API means you can offer it to your customers as well. It's a good pattern to follow, IMO. And if you're going to have that API, then separating the frontend into an SPA is much easier, because you can use that API to drive all the communication. This makes you a user of it (dogfooding).
As for forms -- Almost all form validation should happen both in the frontend AND in the backend, this is a textbook case of something which should be (mostly) duplicated. The backend MUST validate the input at some layer, lest you end up with security issues. But the frontend SHOULD also validate it, because it's a terrible experience to fill in 15 fields, submit, then see a "please correct the errors below" message with 3 of your fields red, your chosen password gone, the captcha to re-do, and that's if you ever manage to get good errors out of the backend because sometimes it just says "This value is invalid" and you have to manually figure out what's happening there (which for normal people means you'll sometimes hear "your X form didn't work" with zero additional feedback).
I’d also add that if you use Typescript with an OpenAPI client generator (https://github.com/ferdikoomen/openapi-typescript-codegen) it can immensely alleviate some of the biggest pain points of seperate backend and front-end. It always used to be a major pain in the ass with the amount of overhead an API change would incur - updating documentation, postman, constant communication between backend and front-end devs, etc. Now I just npm run generate, I see new API changes in my Git client and Typescript errors for code that needs updating.
Also, using a library like Tanstack Query or Rdtk Query can almost completely eliminate manual state management, and kinda makes the whole development experience feel almost like SSR.
I should have been more specific, the codegen alleviates a large portion of back and forth that would have otherwise been spent asking the backend devs things like “why isn’t this working”, or “what has changed”. There is still a lot of communication involved, but it relates more to the business objectives and less annoying fiddly things. For my current project the backend devs are using a cumbersome enterprise stack - the one saving grace for me being that they have swagger (OpenAPI) docs. As a front-end dev the codegen really helps to shield me from a lot of implementation specific backend stuff, as if the interface changes I am going to be informed about it from the Typescript compiler. Also one really great feature is that specific values for validation, such a min/max character length are also exposed and generated with the codegen so that is also another bunch of variables that I can worry less about when I implement clientside validation.
I’d really recommend taking a look at the tool I linked. I see a bunch of end-to-end Typesafety tools mentioned like GraphQL, Protocol Buffers, etc, but they seem overly prescriptive to me, and most of the time you are gonna be working some basic REST service and an OpenApi/Swagger doc is the best you are going to get from the backend devs.