I was worried that an application I was building in Django, with a frontend built with Bootstrap and some LIGHT jquery was making me look like an old curmudgeon but the part about testability of the frontend really resonated with me. It was MUCH easier to structure everything as pytest unit tests and completely rely on Django for all the business logic rather than trying to put state in the frontend and deal with synchronizing states between FIVE distinct systems (remote devices, the Django application, the database, an event stream, AND the front end).
I recognize that I'm not hip or with it, because I really fell out of front end development at the peak of jQuery where it was mostly about fixing browser incompatibilities, but it's nice to see that maybe it went too far in the other direction and we're overdue for a bit of a swing back towards server side.
Just because you have an SPA doesn't mean you need any state in the frontend. Main problem with react devs is just overcomplicating and over-abstracting stuff. The best way to explain it to a backend person is like the same interpersonal problems with overengineered microservices architectures.
redux-query seems a popular library for dealing with API calls in react.
I’ve landed on a project using it.
By default it seems to maintain its own cache in the frontend of all api requests unless you use a non ergonomic feature “useLazy*” where you can give it hint if to use the local cache or not.
It’s completely terrible in a web app! Web is distributed and multi user by default.
End result with the app I’m working on if user a adds an item in one browser session, user b goes to a list view they don’t see the update, they see the redux-query cache.
It’s an over complicated mess for an already solved problem. Have the server send proper cache-control headers and let the browser deal with the caching instead of trying to build fat clients on a web app that should be thin clients.
You are right you don’t need to maintain state on the client but all these fashionable JavaScript frameworks promote doing just that.
Both react-query (that is tanstack query now) [2] and rtk-query [3] include extensive configurability regarding their caching behaviors. This includes the ability to turn off caching entirely. [4,5]
Your story sounds like a usage error, not a library issue.
redux-query seems a popular library for dealing with API calls in react.
I’m having a real hard time being polite right now. Do we have an education problem because where is this person getting their information that they think redux-query is popular?
Yeah I don't know where the parent comment got this from. Every few weeks I seem to see these low effort posts that basically boil down to "javascript bad", but gets a lot of upvotes. And when you read into it, you see the author often has a poor grasp of js, or its ecosystem, and has set up some unholy abstraction, assuming that's how everyone does it.
It’s an application problem caused as a result of choosing the library, a common recommended library, and how the library and its documentation promotes its usage. The tools used were as the tools recommend. Admittedly, joining the project the wrong tools for the job were selected but these are all the react standard supporting libs.
The application should have been architected not to use redux-query, instead use the browser fetchApi and server side cache control headers as we own the entire stack. Today that’s controversial as ”every body uses” and “this is what the docs recommends”
Well, these libraries are doing something inherently complicated on top of just using browser cache headers.
You're only talking about http endpoint caching. These solutions are providing application data caching. These are not mutually exclusive concepts.
The latter offers things like data sharing/normalization across endpoints, data persistence across browser sessions, fine-grained cache invalidation/manipulation, and a lot of things on top of that.
It's a lot harder to manage a cache, and for most apps I never found it worthwhile. But there may be cases where you do want that level of control, like PWAs or an app optimized to never hit the network unnecessarily.
But it's definitely not replaceable with browser http header caching.
I straddle the fence here, I think we jump down people's throats a bit too quickly when it comes to putting names on their new library. But I do also wish we'd stop reinventing things and patting ourselves on the back in other cases.
Eg we are definitely working backwards from SPAs now. "JavaScript islands" were how we got to SPA frameworks in the first place.
I don't have all the history and references, but anyone working in web in the late 2000s and 2010s can attest to how progressively adding in javascript on server side rendered HTML was already happening, even componentizing the server side code with CSS and JS packaged up was very common.
"The term “component island” was first coined by Etsy’s frontend architect Katie Sylor-Miller in 2019. This idea was then expanded on and documented in this post by Preact creator Jason Miller on August 11, 2020."
My only gripe, is that this leads the ready on an alternate history of how we got here.
The general idea of an “Islands” architecture is deceptively simple: render HTML pages on the server, and inject placeholders or slots around highly dynamic regions […] that can then be “hydrated” on the client into small self-contained widgets, reusing their server-rendered initial HTML.
cryogenic lab tech: Welcome to the world of tomorrow!
I started out using React in "islands" almost 10 years ago. The server rendered page would have React components attached to the interactive parts of the page. Fascinating that we're coming full circle to that. Hopefully with better state management and interoperability.
Using a SPA doesn't mean ignoring software engineering principles.
At my work we develop web applications for a mission critical sector (emergency services). We use .net for the backend (we have also used golang in some projects) and Typescript and Angular for the frontend. We follow MVVP patterns, SOLID principles, etc. There are multiple layers, each layer has a well defined single responsibility. Our applications have been quite successful with happy users and great maintainability if I may say so.
There is nothing special about our setup. We could have used Vue.js or react for the frontend. We could have used any platform to build REST endpoints (though personally I like strongly typed languages for implementing business logic and think .net is underrated).
Software engineering might not be as old as say civil engineering, but we've been doing it for decades now and have a rich library of patterns and architecture types to draw from. I've been building software for over 25 years; the technology stack might have changed in that time but the principles are still very much the same or are extensions of the previous ones.
Using a SPA doesn't change the fact that if you want to build good applications, you first have to design them.
> Let’s assume that making a JS change costs twice as much time a Ruby change, which I think is being generous to JS.
Everyone's mileage varies, of course, but this is quite the assumption. It feels like a lack of familiarity/comfort with the frontend or poor tooling.
With typescript and a basic UI library like MUI, this really shouldn't be the case for UI changes. If you're using raw JS and manipulating the DOM, maybe?
The original post could have been a bit more precise on this point. Basically, this math assumes something where the server-provided data changes in concert with the frontend.
If we're using jsonapi, GraphQL, Thrift, or any other protocol that's not HTML, we need to do the following:
- Make the change on the server to support the new functionality. Deploy.
- Make the change on the client to adopt the new functionality. Deploy.
- Remove the old functionality from the server (optional)
Because the client is a separate application, it becomes riskier to deploy those changes together. I need to think about it more as a developer.
With server-authored HTML, this separate client + server deploy is not required.
There are a couple of reasons this is not convincing either:
- Other factors can often dwarf the separate deployment overhead, especially given that the deployment steps are done so often it will force the team to make it efficient and get used to it.
- There is no hard requirement for separate deployment in the first place, if we are just talking about react / spa you can deploy it in a single step. (Not saying you should)
The point is: yes there is quite a lot of overhead. From separate deployments, from separate state management and I think the big ones are often having two different programming languages and having to align schema on frontend and backend. It is hard to deny this. But then saying that because of this overhead, these kinds of apps take 2x time to code implies denying there are benefits as well, that under given circumstances can outweigh the overhead.
I think it is more interesting to assume that in some cases the benefits outweigh the cost of the overhead, and in others they do not.
Not necessarily. Most of Rails+React apps I have worked on have had the frontend code live in the same repository, and get deployed during the same step.
Yes, you have to keep API compatibility in mind when doing changes, because long-lived sessions might still exist. But has not been that much of a big deal in my experience.
Not necessarily. We write Typescript for front and back ends, using statically rendered SolidJs, skipping SSR, and hosting the corresponding Typescript in Lambdas.
Yes, we use Lambdas but the CICD pipeline is shared and currently deploys everything everywhere every time though it will be more efficient to detect and only deploy deltas (there are some minor out-of-the-box detections of non-change but further optimization is very easily possible). For now, it's more important to pursue product market fit - the deploy is ~4 min per environment which is plenty good for current purposes and could easily be parallelized among other obvious and easy wins.
OVERALL: I recommend the Serverless Framework but SSO wasn't supported at the time I started building so we use the CDK for deploying everything. The CDK stacks for the S3 bucket (etc.) and API are separate but that's a matter of factoring for clarity since it would be fine to have one big stack. For similar reasons, I factor the API and API deployment separately, alongside the WWW and WWW deployments. The entire company is a monorepo with a single command at the root that, beyond one-time account bootstrapping (which also uses CloudFormation and CDK), triggers scripts run locally or remotely to execute unit testing, deployment, and acceptance testing in a progressive multi-account deployment (on main). The CICD script installs dependencies, runs tests, identifies itself and uses that to assume account specific roles to deploy into the individual environments. This is all pretty excessive for a startup but seemed like a worthwhile and more secure foundation for actually trustworthy experimentation in delivering solutions into some of people's most sensitive private spaces and visions to go deeper.
Meta-note: I accept that the separated pieces of the infrastructure have timing deltas and that some bugs could arise out of this once we've scaled. This is never not a problem but can have diminishing windows and/or effects with investment. This can be solved either by coding the API to handle current and current-1 contracts or maintaining concurrent current and current-1 lambda version deployments, where divergence occurs. None of that contradicts a single deployment of consistent code. There are deeper solutions with greater financial efficiency but I'll need a wild success scenario before those make business sense to invest in (monoimage k8s, knative, and so on).
LAMBDA: we have built configuration that specifies the build entry points for tree shaking so that our deploy sizes are tiny and that is used by the CDK pipeline too. Our data tables are declared there too so that code and deploy share config. The Lambdas are grouped by event type (i.e. HTTP/ApiGateway, S3, Kinesis, EventBridge, etc.) and our declarations are structured according to generic Lambda defaults, a source-event-specific defaults, and a function specific declaration, allowing overrides at every level. This may sound complicated but it very cleanly organizes the configuration rather compactly, providing incredible clarity, and making scope of effect explicit and consistent.
Everything is written in TypeScript which covers internal compile-time type safety but I have written a layer of middleware for the Lambdas so that they declare their contracts (that uses AJV to validate schema to type equivalence [JSON Schema is far more specific of course]) and entry points and enforces schema compliance (engineering requirements) at all boundaries in and out of the code base (i.e. receipt of API calls in client, receipt of client requests to API, S3 data, database puts/receipts, and so on).
This got long so feel welcome to reach out (see profile) if you want more specific detail about any specific piece.
The fashionable thing for a while now has been to write your react webapp as a single app.
Here is one example of a "fullstack" react template: https://create.t3.gg/
Interesting setup. Looks like getting to a zen state like this would have required them to migrate their backend from Rails to ts at some point. I can understand the engineering decision not to do that.
yeah and it sort of sucks in comparison to most other server-authored HTML solutions, in this statement I am of course thinking of Next but I suppose various forms of suckage will be found in other solutions.
And to me both suck, compared to traditional template rendering like Jinja2 or Django Templates and those suck compared to SXML. React because of JSX and NextJS because of JSX and its assumptions about directory/file structure mapping to request routes, unless you change routing. JSX templates have that same feel, that PHP has from back in the day. Treating HTML as a string, implementing a wannabe HTML, that is not actually HTML, but slightly differen (for example the class attribute of HTML elements, or Fragment, <>) and enabling people to put JS logic inside the that string, mixing everything again, requiring to have a separate parser.
Separate parser is basically what Jinja2 has or other templating engines like Django templates. React could have used any templating engine that already existed.
But compare it to the elegance of SXML and treating HTML as the tree that is it, as structured data, enabling pattern matching on that, avoiding the need for a parser, and all other things that are in the language. Use. Structured. Data. It is so simple.
Mainstream frameworks got a lot to learn still. They are still on the Kindergarden level of treating HTML as a mere string for most parts.
Absolutely, this is one of the main assumptions where the blog falls apart. What takes more time and carries more risk, really depends on context. Boring, but unavoidable. This is another one:
> when compared to a world where that change isn’t risky (server-rendered ERB)
Server rendered html templates a la PHP - which is what ERB is, may be not risky in this smallish project with likely a fairly straightforward UX and seasoned rails devs, but it can be risky in others for sure. I think a lot of the motivation to embrace what react began was a desire to move out of a tangled mess of spaghetti templates, to be able to use means of abstraction and modularity as powerful as regular backend code. Frontend devs want to create and use components. You cannot create a component with html templates, not really. It will be a mess.
Moving from server rendered html to an api + spa architecture has quite an overhead of course. Just like adding a separate backend service. That price should be worth it. And a good developer can judge whether in which context that is the case. But pretending the benefits that motivate such a change just never justify the costs doesn't make sense to me.
The cost of a change is a very, very complex measure. Anyone who has a simple answer to it that is universal, true and useful will win a Nobel Prize. This is because the cost depends on the person who is making it and his peers, on its effects in the future, on the project of which it is a part, on luck and on the larger ecosystem in which it is done. There are just way too many parameters.
My experience with very highly paid frontend developers is they like to spend hours and hours (and thousands and thousands of dollars) building out little libraries and components and frameworks that will enable other teams to be faster. Except this never eventuates because things rarely turn out to be reusable along the right axis so a new component or library or framework is developed to solve the problem.
On top of this UI developer propellor-heads love to spend time (and money) pontificating on abstract theories about functional programming and homomorphisms and endofunctors so they can render some text inside a <b> tag. It's how we wound up with utterly ridiculous pieces of code like the "hooks" API in React.
Can’t get promoted pumping out 10 great pages. But a library that you can claim will enhance the productivity of 100 other engineers? Now that’s IMPACT!!
Except you’re at a company where everyone has figured this out so now you have 4 competing libraries with their own teams which are all 1/2 done making every engineer less productive cause they all have bugs and slightly different priorities.
this is exactly the frontend team from a previous role. we were losing millions a month and had 2 major cuts within 4 months - and instead of cleaning up or simplifying our bloated frontend, the teams responsible for it started building new component libraries for the rest of the org to use on future pages
I also get the feeling that modern frontend is a massive money pit but this seems to be a leadership problem. I wouldn't go so far as to blame the IC. There are developers over-engineering in every ecosystem.
Something about the psychology of front-end - not quite as hardcore technical, a little more humanities-aligned - perhaps makes them even more susceptible.
The self-consciously cool kids are always going to be more easily swayed by fashion than cave hermits.
You forgot the part where everything has to be redone every 5-10 years despite grand allusions of reusability because of the cyclic nature of the frontend market. The JS framework proliferation is largely driven by skills becoming obsolete (or needing to become obsolete for economic reasons) as younger frontend devs move in who want to carve their niche and distance themselves from "horrible" previous-gen unmaintainable and wayyy overengineered stuff. Which was objectively unmaintainable either from the start as a work of love of a developer who put all his thoughts into it so it became incomprehensible ;) or became unmaintainable when later developers (who couldn't care less) had to violate the original grand vision of state encapsulation or hypermedia architecture or whatever for a trivial business form app.
I guess the good thing is that comprehending our absurd web frontend creations is beyond current LLM's capabilities.
I've done a lot of back-end and a bit of front end development. You're correctly identifying a crappy outcome, but incorrectly attributing the effect of shitty developers and project management with whole disciplines and common practices within them.
I think the author was talking about React specifically.
I've worked in JS, TS, React, and RoR, and yeah I'd say making a change is probably twice as quick in RoR as in React.
The thing is that Rails is an opinionated framework. If you do things that the framework is designed to do, then it's very very easy. If you go off-piste and have to fight the framework to do the thing you want it to do, it gets very hard very quickly.
React is less opinionated (about most things) so the converse is true; it is slower to write stuff in, but there's less constraint.
I feel the comparison is really hard. Rails really is a framework that solves anything but the business logic for 80% of your app. React is really a library for rendering components and everything else is your decision to pick or build from scratch. E.g. Rails has opinions on how to build forms while React, a supposed frontend framework, doesn't have anything baked in specific to that. Sure the community has opinions about it but React doesn't like Rails does.
There is no free lunch though. Typescript and whatever frontend stack we might go with will come with their own drawback. It doesn't mean the trade-off is never worth it, but we better keep in mind that adding transpilers and a truckload of external libraries does have a maintenance cost.
I wouldn't touch a React project without Typescript. But if you use something like Web Components (or Stimulus etc) where you compartmentalize small bits of UI into distinct reusable components, JSDoc gets you 90% of the benefit of Typescript without the baggage.
Also it depends from API response. It could vary from FE dictating schema or backend making hard orthogonal domain modeling API.
In first case FE is productive there is no need to transform data but makes BE a hot mess. Otherwise FE have to maintain layer of code to convert BE data to presentable UI data. It's harder but allows to decouple UI reqs from changes along all stack.
Yeah this seems like an insane assumption on a language basis. Ruby has no static types (or not very good ones as far as I know) and is very hard to follow due to using "magic" so much.
I've contributed several features to VSCode (Typescript) and it was relatively easy. I have completely failed to do the same with Gitlab (Ruby) because the code is so hard to navigate. I did manage to add some features to gitlab-runner but that is written in Go, which again is much easier to follow than Ruby.
I think they are really talking about client-side vs server-side rendering. Server-side is much simpler.
FYI - There's some neat ways you can embed React components inside Rails templates. Basically - embed the props in a template-managed `script` tag, and use Stimulus to mount the react code, passing in the props read from the DOM. Now your React is pure state-to-view, no need to synchronize anything, - it's really just a handful of React components instead of a full React app.
That said, AFAICT, there's just two advantages:
1. Those annoying little UX doohickeys that actually DO want that level of interactivity
2. You can use any of the vast library of existing React components (for me, that's been react_big_calendar)
As a bonus (and, why I rolled my own, since `react_on_rails` doesn't support these), and with a bit of tweaking:
1. It plays nicely with Turbo. I can use Turbo to update my React props and it just... works.
2. You can embed a template as a child of the React component.
2a. This also plays nice with Turbo.
It sounds a little screwy, but so far it's working well, and it feels like it lets me use the right tool for the right job - aka, Rails for everything except the stuff with extremely high interactivity.
I intend to! And to wrap it in a gem; I’ve got it partly there, but it’s a currently a mess as I ran into a bunch of “oh that didn’t actually work” problems at various points. I’ll post a link later…
Edit: Ach, sorry - it's going to be awhile, when I went to roll my own I did it inside my project, so it's not even close to being available as a gem :/
HN is not real world, just like how Reddit is not real world.
I am a FE with 10 years of experience, and has tried, and tried really really hard and multiple attempts to make HTMX works well.
Doesn’t work. UX is much worse, code discoverability is much worse, slower to code in, everything is messier than just plain React SPA with JSON data. Terrible, terrible DX and UX.
Seriously, there is a reason why despite all the rage in going back to multi page Django/Rails app, very very few people actually take it seriously. You just don’t hear the negativity because most folks just tried it, saw that it is worse, and moved on without writing a blog post.
I've contributed to all kinds of frontend setups; Elixir LiveView, React, Vue, Angular, HTMX and many more.
I've yet to find a frontend scripting solution that works well. My current stance is to have the frontend as thin as possible, no matter how it is written. Have your domain logic on the server output Plain-Old Data structures (JSON or similar) and render them with stateless, dumb views, be it a template, Vue, React or whatever.
A clear boundary between the domain logic and view is important. Rails templates that can basically access anything is a terrible idea.
I have similar kind of experience and made similar conclusions for myself.
In addition to the points you have made already, I would like to add that almost every larger project needs a lot of business logic on the backend side anyways. There is no possibility to have this logic in the frontend and there never will be (for security reasons at least). So given these circumstances, we usually already have quite a few people experienced with - and very efficient in - these backend technologies.
So why would I spend a lot of time re-creating all kinds of routing, models, properties, etc. in an SPA? We currently run an Ember SPA for our largest project and 1/3+ of the time spent on it is pure waste because it is simply additional work to facilitate the use of this SPA at all.
In every project I've worked on, the interactive and dynamic elements actually used that are written in JS end up being a lot fewer than originally anticipated. Unless you're building a product where the majority of the functionality relies on instant, realtime updates such as maybe a streaming site with chat, etc., building, maintaining and extending an SPA is a huge overhead that offers little benefit over "dumb", static views with small, isolated interactive components.
> Unless you're building a product where the majority of the functionality relies on
This is a huge problem in the ecosystem. People want a landing page, so they reach for some full-stack SPA backend+frontend framework that is hip today, which is absolutely bananas.
Sure, if you're building web app with lots of dynamic and interactive elements, go crazy, because you'll probably need it, lord knows you'll get tangled up in state management no matter how clever you think you are.
But for websites that aren't trying to became the new Google Maps/Figma/Whatever, simple and basic templating patterns won't just be faster to develop, but easier to maintain and a better experience for your visitors to use.
My experience exactly. Why one would do that anyway? Not listening to experienced engineers and being blinded by modern FE hype. Thinking just because many other businesses do it, one has to do it too. Then decision made by non-technical or not too technical management people.
And sure enough, then came the self inflicted workload. "Oh we need to change the router.". A problem you do not have with any popular mature web framework on the backend. "We need to upgrade to NextJS version 149, for feature blablub." Which would come naturally with something like Django or other traditional web framework. "We need to upgrade NodeJS!" ... and so on and on.
While all of what the FE actually did could have been just render static templates and a few lines of script.
Companies choose their own downfall by following the FE hype trains. The result are the shitty web apps, that don't need to be "apps" in the first place, but could simply have been static pages. It is quite a comedy show and I would laugh, if it did not affect me negatively.
I also have a lot of experience with various setups and front-end technologies, and I couldn't agree more!
Furthermore, I'd say this: if you can't simply serialize your view-model and send it to the client because something might get exposed or because it's a complex object with embedded logic, your first priority should be fixing that. Only after achieving this should you even think about changing how you handle the front-end.
It's a really strong selling point that you can use a popular FE framework for all the templates, but at the same time almost completely avoid state management.
> but at the same time almost completely avoid state management
Unless you're just building simple landing pages (I think the context is "web apps" here) or something, you might not have removed any state management, you've just moved it elsewhere.
So the question is, where did you move it instead? The backend?
That is a good point, and I can see that I probably did not communicate what I meant clearly enough.
In my experience most of the state management in FE apps is about fetching and handling data from different types of APIs. With inertia you get a very simple abstraction in that each page gets its own little API. Then inertia takes care of feeding the data from that API to the rendered page when you navigate to it.
For that reason the page can be a "dumb" component, and there really isn't much state to manage.
If the app needs modals, dropdowns, forms e.g., you will need to manage the state of those in the browser, which I think is very reasonable.
Obviously there can also be situations where you'd want to have a small part of the page to fetch some data asynchronously, and for those you'd need to use something else - inertia doesn't do everything.
Out of curiosity, what difficulties have you faced with Elixir LiveView? I am developing in it right now, and am enjoying managing state and interactivity in one codebase (I like how everything is channeled through the socket).
My primary complaint is that it is hard to test (compared to "stateless" pages) and that the whole thing feels complicated.
I also feel like the learning curve is pretty steep and you can't just have a random, experienced non-Elixir dev join the project and have them fix something. They must be comfortable with Elixir & Phoenix before they get productive. I feel like it is multiple layers of complexity and uncommon patterns.
Other than that, I think it is very cool. I have very strong mixed feelings about the feature hah.
If you handle all interactivity server side so that the user can’t do anything at all without a round trip, sure. It’s just a terrible app for users with latency/patchy connectivity. As soon as you try to mix in slightly nontrivial client local state and transforms it becomes the most retarded JS imaginable.
This is the common misconception of LiveView coming from the JS community. LiveView is JS. It has a whole optimistic UI layer that solves all of the problems you cite. The UI from state updates coming from the server or the client doesn't matter because the reactive UIs of SPAs still require data updates from some remote source. So if we're talking about latency that latency is going to exist for all application types.
Where did I say it’s not JS? I said it becomes the most retarded JS imaginable. I have used the “whole optimistic UI layer”, hooks and commands. What happens is local diffs have to fight server sent diffs, at every level, resulting in more tangled logic than jQuery apps. This does not happen when you merely have to merge state and the view is a pure function of state.
It is very easy to have very important choices made inside a rails template, like permissions (can X access Y?) and it is similarly easy to ignore permission checks and just query anything you like.
This makes it also very easy to end up with N+1 issues that are not caught in tests (because the tests don't render views), "forgetting" to scope the data (rendering more records than the user should be able to access) or rendering sensitive attributes the user should not have access to.
Even with tests that do include rendering the views, it is very easy to have a test like:
it "renders my posts" do
post0 = create(:post, user: current_user, title: "Foo")
post1 = create(:post, user: current_user, title: "Bar")
response = get "/my-posts"
document = parse_html response.body
expect(document.css("tr td.title").map(&:text))
.to match(["Foo", "Bar"])
end
Now there's so much wrong with this test, but the primary issue is when the view does something like this:
<%= render "posts", posts: Post.all %>
The test implies the document should only render the current user's posts, but the view / template actually renders all posts. You don't want to test this kind of logic by inspecting HTML, because it is error-prone and expensive to test this way.
What if you want to change the HTML structure? You'll end up rewriting all these tests, and it is VERY EASY to make subtle mistakes when rewriting the tests, resulting in false positives in the future.
Instead, I think you should separate this logic to a model, not to be confused with "activerecord classes" - I'm thinking of a `UserPosts` model, like this:
module UserPosts
extends self
def get_user_posts(user, opts)
user.posts.with_opts_or_something(opts)
end
end
Then you also disable automatic loading of relations (forgot the config name) and, by convention (or enforced in some way), never refer to any model modules or classes in a view (or any method called by the view, like the helpers).
Your controller will likely look like this:
class UserPostsController < Whatever::Base
include UserPosts
def index
@posts = get_user_posts(current_user, page: params[:page])
end
end
By keeping the domain logic inside specialized modules per access scope (i'd have separate `Posts`, `PublicPosts`, `AdminPosts`, `ModeratorPosts` modules), you can test the logic in tests per module (including tests what the module SHOULD NOT access). Then, when writing the views and controllers, you don't need to re-test or re-remember to test the "should not" cases - the test cases you're easy to forget.
You can also design the modules in a way that they only load (select) the properties that context would be allowed to access. If you have sensitive data (like a user's real name or email), you don't even want to load that property when loading the users from a `PublicPosts` context, since public posts should only render the user's id and public nickname for example. You can also wrap the posts/users in presenters using whatever fancy gems you fancy, as long as it gets the job done.
In an ideal world, I'd lock down Ruby templates to only have access to previously loaded data via instance variables and helpers, nothing else.
It is a bit hard to explain, since I have limited time to address it properly, but I hope I get the point across.
I'm a freelance webdev with 15 years of experience, and recently I've made some new projects with Symfony Stimulus & Turbo to great success.
A few thoughts:
I tried just htmx too, too limiting. Stimulus/Turbo combination is much better.
Use the right tool for the job. Highly interactive app, like an editor? Use react or similar js framework. Mostly page/document website? A backend framework is much faster and easier to develop, and much simpler to test.
A blend of both? Drop in a React component where needed on a given page! People forget (me included) that even React can be mounted into a single DOM element.
With all this framework nonsense its hard to forget at the end of the days its all just javascript.
If you're doing something something reasonably small, using preact rather than react and then wrapping it into a web component so you can just ... put it in there ... is a really nice option to have.
(it may not be the right option in any given case, but it's worth knowing it's there even so)
Preact is definitely a good choice if you're looking for something lightweight. React-dom was already relatively hefty, and seems to have gotten even larger in version 19. Upgrading the React TypeScript Vite starter template from 18 to 19 increases the bundle size from 144kB to 186kB on my machine [1][2]. They've also packaged it in a way that's hard to analyze with sites like bundlephobia.com and pkg-size.dev.
I'm not too sure about HTMX in particular, but my Rails app's FE is just HTML and Stimulus/Turbo. I'm not sure why you think it simply "doesn't work".
To me, it's a lot simpler. I use forms and links and render HTML templates. That's it.
I don't need to worry about building and maintaining a JSON API just to serve the front-end. I don't need to worry about distinct sets of routes and models. There's just one repo with one build pipeline and test setup. There's no need to worry about front-end state at all, since I'm just using plain-old links and forms.
I'm not claiming that there is never a use for React or its ilk, but I am genuinely finding it hard to understand how one can assert that this simple HTML-based approach is categorically worse in all circumstances.
In my context, the simple approach works. If I were working on something that had a high degree of inherent complexity on the front-end -- maybe a web-based video editor or some kind of WSIWYG productivity tool -- this approach would almost surely fall apart, but that's the point of engineering: Choosing the right tool for the job at hand.
The truth is in a similar vein but more general - most just pick the stack they are most productive in, whatever that may be, and move on without writing a blog post.
For less frustration when reading such posts that are written, read the author as writing for themselves, reporting the pros and cons for their very particular situation, and see if there's some nuggets to be found in that context.
Don't read them as telling you those same pros and cons apply to your situation -- even if they veer into implying they may :-)
This may depend on a type of website/webapp one is working on? I have a suspicion that sometimes HTMX may actually fit nicely (e.g., for an online survey), sometimes React-like framework is the probable way to go (e.g. a marketplace app), and sometimes it could be that neither is a good option (e.g. games).
The main problem is that it is not really viable to start with HTMX and add react (or another frontend framework) later because you end up having two completely separate stacks that are very incompatible with each other.
The worst sin a large codebase can do is being inconsistent.
>>> You just don’t hear the negativity because most folks just tried it, saw that it is worse, and moved on without writing a blog post.
How does your approach contribute to the discussion? You created a new handle named ‘htmxsucks’ solely for the purpose of making this comment! While it’s perfectly acceptable to express negative opinions about a technology and be vocal about them, doing so anonymously in this manner undermines your credibility.
I too, am someone who creates a new handle for every single comment, and I would like to point out you too lack any meaningful point aside from that personal observation. Yes, it is cowardly, and I agree with the sentiment of being forthcoming with identity when making negative statements related to your field. It's actually less isolating, despite one's fearful assumption. But that is still, regardless, a point completely unrelated to the actual "discussion" you're putting on the pedestal.
I’m genuinely impressed that you took the time to create a handle based on my name, replacing “me” with “you”! I’m upvoting you for this thoughtful gesture!
I have a side project that was using Vue, not even React, and every time I went back to it, it was hours of bringing everything "up to date". Everything seemed antiquated every few months I'd go back to it. It never moved past the blank landing page.
Then I moved to HTMX and I did more in 5 weeks than I did in 5 years.
> it was hours of bringing everything "up to date"
Why? We still have Vue 2.6 (not even 2.7 with compAPI) projects living and chugging along just fine. Why do you feel the need to keep everything updated to latest or whatever?
I think only people who follow frontend hype don't take traditional web frameworks seriously, especially some as mature as Django or Rails.
It may be, that very few people these days actually know how to make a website without reaching for hyped JS frameworks. The thing is, one needs to know more than just JS. One needs to know an actual backend language and learn the framework. Many web developers these days don't have this set of skills, might not even know another language than JS, even though it is not hard to learn.
Not every website needs to be a "web app". Not every website needs to be some SPA. Many are better off without being an SPA. Once you are not building an SPA, many other frameworks become very viable and proven alternatives, among them Django and Rails.
Also underappreciated thing is the community. For any decent/widely used framework, the architecture or other aspect is good enough for your usecase. It's unlikely that you would get significant gain due to the framework for all usecase, but having a community where every question you could possibly have is in github issues is very useful.
Im a gen z and the best experiences were with Angular and React. Sure, it's not always pretty, but I'd much rather have a framework that pushes me in the right direction. If I had to use HTMX for work, then I would've guaranteed used it wrong. It's just not worth the reviews and hassle if the result is less standardized. It's also harder to find HTMX dev's when there's so much React devs (or devs willing to try React, seriously if you've worked with one CSFW then React is child's play)
> If I had to use HTMX for work, then I would've guaranteed used it wrong.
As someone who's been doing web dev since the 90's and is currently leading a project that's built with HTMX and having onboarded a few younger/junior "react devs", you're not wrong. What I've seen is that there's a whole generation now who just don't know how to do things in a different way than by building a SPA. The difficulty onboarding those devs is always in getting them to unlearn the patterns that React/Angular/etc. have ingrained in them. I've reviewed PRs that were a mess of complicated HTMX attributes, backend logic switching on headers, etc. and pointed out that all of it could be replaced by just, like, using a plain old HTML form submit or `<a href="..."`. I wish I were kidding. They almost always start out massively overusing HTMX out of a fear of triggering the dreaded full page reload. But in a non-SPA world, with a fast backend, full page reloads take milliseconds because there aren't MBs of JS to download and execute and a bunch of client-side state to reconstruct.
> It's also harder to find HTMX dev's when there's so much React devs
For someone who is familiar with basic web technology (like the 20 year old version with HTTTP/HTML and minimal JS/CSS), it only takes 15 minutes or so to learn HTMX (then maybe a few days of building where you pull up the docs occasionally to remember the names of the attributes). The idea of someone calling themselves an "HTMX dev" the same way we have "React devs" is ridiculous.
As someone who hasn’t touched fe dev since vue alpha… I chose next, then remix. Then moved to svelte before I went too deep. The application I am writing could easily be done in django or .net with some simple js - but with svelte it all ties together so easily. I guess I could accomplish similar with partial views or jinja2 templates.
My experience with it is, one there’s no decent templater for nodejs, two this web1 like architecture really makes no sense as a developer. Everything is a subpage transfer rather than a meaningful operation/update. I came from desktop ui background (delphi, vb, gtk, qt, appkit), not from web. The web is all fucked up, tbh, it’s not only htmx. But at least spas vaguely resemble how normal apps function.
I see. HTMX and others target the browser, which is primarily an HTML renderer. So there is nothing inherently bad about page transfers. That's what hypermedia is about.
React et al try to create a different paradigm on top of this. And that makes it like building a desktop UI AND a server app
To me, this is not in anyway better than building something for the browser - pages and html.
I am surprised that Unpoly (https://unpoly.com/) doesn't have the same recognition as htmx/stimulus. I blame the obtuse project name.
Wish the web spec just standardized a mechanism for partial page load/render. It would become the most frequently used developer technology feature of the 22nd century.
I am starting a new web application frontend project soon calling a backend REST api. What would you recommend in 2025? I don't have legacy requirements. React? Vue? Something else?
Use the framework that has the libraries you need, React has a lot of ecosystem around it so it tends to have everything. You don't want to spend time
integrating a plain JS calendar library into your random framework when you can just use react-calendar.
So look at your requirements, check the framework for libraries and tools (like deployment, hosting, monitoring etc) available. The libraries you use are much more important than the framework.
Do note that although there are plenty of react chart libraries they tend to be quite under-performant. Tying chart rendering with any frontend framework building blocks ends up with bad performance. If you are dealing with >10k data-points that update often I recommend using a plain-js chart library.
Which framework-specific libraries do you even need? It’s UI, like forms and buttons and inputs and tables. I can’t imagine e.g. choosing between GTKmm and Qt over “libraries that I need”.
deployment, hosting, monitoring etc
Isn’t this backend-related? Generally framework agnostic?
Deployment and hosting is just publishing a Vite/etc bundle, right? What is framework-specific frontend monitoring?
> It’s UI, like forms and buttons and inputs and tables
For the most part yes, until you have a very specific requirement like complex drag and drop interactions or a complicated UI component like a calendar view. Also don't underestimate how much work it is to make a good component library from scratch, picking a framework based on the available gui libraries is important. I would say you should pick the gui-library first and then the framework.
> Isn’t this backend-related? Generally framework agnostic?
Depends, sentry.io for example has a pretty good NPM package that integrates well with react giving more detailed errors. Some deployment/hosting solutions integrate better with some frameworks (although it is mostly a concern for SSR or static site generators projects).
I was down on the ergonomics of Web Components for a few years, but recent work has me actually excited for them as the present now. You can get some nice "Progressive Enhancement" experiences with them now.
If you are starting fresh, I'd consider taking a look at one of the lightweight options like lit [0] or FAST [1] for building your own. (Later this week or this weekend, I'm going to try to document building Web Components with my Butterfloat [2] because so far it is turning out great in my current hobby project and about to the point where I'm going to recommend it to production projects.)
(ETA: Also advice I wish was more common in Web Components documentation: You don't have to use the Shadow DOM at all. Much of the complexity and confusion in Web Components is interacting with the Shadow DOM. There's a lot of great advice on why you might want to use the Shadow DOM. There's less great advice that it can be YAGNI and it is so much easier to style Web Components when they don't use the Shadow DOM, especially in your own Web Components for your own FE using a common style template like Bootstrap or Bulma. You can just ignore the Shadow DOM and use the "real" DOM.)
In one of the projects I worked on years before, the pages are served by Django 2, and all the fancy interactivity is handled by AngularJS (v1) (think datepickers, galleries, multi form, etc).
We would use the same controller name, and just load different JS for different pages.
It was an odd stack, but it served us pretty well.
Would you please stop breaking the site guidelines? You've been doing it repeatedly and we've asked you to stop many times. Here are another couple of recent cases:
I really don't want to ban an account that's been around so long and has contributed many good things in the past, but it's also not ok to degenerate to this level. Also, it sets a terrible example for other users.
p.s. I have no idea whether the GP was right or wrong, but it doesn't matter. We need you (i.e. any commenter here) to follow the guidelines regardless of how wrong someone is or you feel they are.
Server rendered HTML is all well and good until you want to add native apps or a first class API layer. At that point, it makes more sense to have the web be just another client and move as much business logic into the API layer as possible.
A native app is more than just translating each html page into a screen. You’ll likely want to build a data model that you use throughout the app, instantly load as much of the next screen from data already fetched as you can, etc.
Having a flexible API tier makes that more ergonomic.
Nobody said anything about translating pages into screens.
The point is that the data model (and hence, the API design) applies equally to a web UI or a native application. The
issues you're raising also matter for making webpages fast. When you think about the data model design before you make the presentation layer, in almost all cases, the choice of what you render is basically a straightforward transformation.
> Nobody said anything about translating pages into screens.
Well, someone did. The person above them said you can just map your Rails html routes into JSON returning routes (translating pages into API endpoints).
Which obviously gives you a suboptimal API since data access is tied to Rails pages instead of having a flexible, deliberate API.
And once you build and have to maintain the latter along with the former, you are now duplicating work. It's a familiar issue for people who have built SSR apps.
> The person above them said you can just map your Rails html routes into JSON returning routes (translating pages into API endpoints).
That was me. And no, you misunderstood. I said "controller logic" -- Rails (and any other decent web framework) allows you to map routes to endpoints in the code. In the simplest case, that endpoint could be used for an API response or a webpage, and just render different things. Alternatively, you can even have API routes mapped to a slightly different top-level endpoint, which does the vast majority of its work by calling the same set of downstream methods as the webpage version. Or a thousand other variations on the theme.
In short, assuming that you don't just structure your code as one gigantic function for each route, it's not hard to do, or hard to maintain. You do have to think a little bit about how the controller logic fits in with the API and the webpage structure, and I contend that this is the actual, practical reason that we've seen so much burdensome (over)use of React, GraphQL and the like -- those things are separate teams at many companies, and the "decoupling" theoretically unblocks the teams.
First class API layers and native apps require such a massive amount of work (and money) that your app emitting HTML is the least of your problems.
This is not 2011 when every website was building an "app" for native experience. If you are not building an Uber or an AirBB, you will probably manage.
People in the comments talk all about their favorite pet tech stacks with only a single purpose: how long it takes them to write code. In front end logic that typically means putting text on screen or interactions.
Years ago I decided to not worry about those concerns and it turns out those concerns are irrelevant. Writing content, really all front end logic, is as fast as you can type on a keyboard irrespective of your tech stack. Just about everything else is over engineered insanity. That was even true back in the IE7/8 days.
It became apparent to me the only thing that mattered is time to refactor. The larger the application is the more true that becomes. The things that help with that the most are type annotations on everything, high execution performance, and fast test automation. Everything else became a distraction or noise that got in the way. The application does what it promises or its defective. It can be modified quickly or good ideas are abandoned for risks or costs.
So I don’t worry about tech stacks and spend too much energy on execution speed.
> Let’s assume that making a JS change costs twice as much time a Ruby change, which I think is being generous to JS
I don’t grok this part. Based on my experience with RoR and JS/TS, making changes in TS-land is much easier and quicker than dealing with Ruby.
Is this just a preference/experience thing in the end? For you and your team RoR is faster/easier, so that makes it the better choice. For a different team JS/TS may be faster/easier, so that makes it the better choice?
I should have made the distinction between client-side and server-side JS/TS. Familiarity and expertise will be a main driver of productivity for a team, regardless of language/framework. For us, that's RoR.
Client-side JS however has a multiplying property, where we often need to write more server-side code to accommodate the growth in client-side code. If the client-side code is providing undifferentiated value (e.g. authoring HTML), we now have more pieces in our system to accomplish our goal (author HTML). What's been surprising to me is that you don't need to author HTML client-side to have a reactive experience. With Turbo, Stimulus, and server-rendered HTML, a great experience is possible with fewer layers.
I think the power of fat clients comes when you have different consumers of the same APIs/logic. Like a browser app or two, maybe backend services, a few task queues, etc. Then having a clean separation between client code and business logic becomes super valuable.
In my experience with SPA we got to a point where my team could go weeks, even months, without having to make changes in server code. Whole new features that were fully supported by our existing APIs because they were written as reusable APIs. If you’re having to write a bunch of Rails to support the growing client code, you probably didn’t need a separate client yet.
But when your codebase gets to that point even Rails is just a frontend really. So it’s mostly about which tradeoffs you prefer. Unfortunately I left Rails right around the time Turbo was becoming a proper thing you could use so I don’t have the best feel for what it’s like.
Thank you for writing this all up. Just curious if you ever considered switching away from Ruby? I think many people are living in parallel stacks (TS, Go, Python, Rust) and it would be interesting to hear how it’s been going more recently in that ecosystem from your perspective.
As to rendering, I’ll be honest and say that my code has moved more towards client-side (using ConnectRPC and my framework ojjs.org—-shameless plug :), but I love that you have had success with a different path. Super interesting, and thanks again!
I don't have a reason for switching away from Ruby at this point in my career. Things can always change down the line. Maintaining multiple languages at the same layer sounds like a personal nightmare to me. I'd rather learn to write PHP and have that be the only language, than to write Ruby+another language on the server-side.
We're building our company on Rails because we think it's the best choice for a young company, since it allows us to respond to customer feedback more quickly. That's what we're optimizing for right now!
Reg. #2 - I returned to frontend dev. after years for a hobby project (and even earlier, my frontends weren't very complex, I could get by with jQuery in the pre-React days), and I am surprised to see this is popular (or at least a supported feature everywhere). I would also think #2 is dangerous, but I am wondering if its just me being simplistic. Aside from a thin layer of reactive controls, when do people need #2?
Watching Meta rewrite Messenger twice without success was enough for me to never touch React for any large project, especially after that botched e2ee chat rollout.
I didn't say Messenger wasn't successful. I said that Meta rewrote Messenger twice and did not meet their internal goals both times.
Even today you can see Messenger completely break down if you have to sync for more than ~30 seconds. JS console fills up with errors about your broken state as you start to lose messages. Local storage is out of sync, session state breaks, and it's all right there in the console. It's been like this for years on WebKit. React just has too many bugs for a complex behemoth like Messenger.
React Native is just as bad and basically everyone I know in real life can corroborate lost messages, broken group chats, horrible photo experiences, and memory leaks!
You can just look at Messenger vs WhatsApp and the difference is just night and day in the user experience. The e2ee backends are the same (according to my pcaps, I could be lying), it's purely the front end that changes - and you won't find anyone that says Messenger is better than WhatsApp.
The only UI framework I’ve ever used that I didn’t absolute hate is DearImGui. I realize it doesn’t produce polished, professional looking UIs. But my god is it the only thing that doesn’t suck.
JavaScript and ReactJS are at least 10 times less efficient to write than C++ Dear ImGui. That’s so crazy.
I feel the same about DearImGui. Want a list of sliders, bam, it’s done.
So I started working to create my own UI framework with some of the DearImGui feel but being a bit more scalable.
Recently I just added basic CSS [1]. Super fun to get it working but it’s been a lot of work combining UI styles. But it’s cool getting 60fps live animations in a 4mb binary. Hopefully CSS can help get it looking good.
Did you read my whole comment? It feels like you didn’t read my whole comment. Because I said “I realize it doesn’t produce polished, professional looking UIs”.
I don’t think that’s an intrinsic quality of a DearImGui type API design. I’m reasonably confident it could produce a professional end-user facing UI. And that it would be perfectly performant and battery efficient.
Yeah, drawing everything to the screen every frame makes a lot of things easy. You can just update state and it will get drawn on the next frame.
DOM UI libraries like React have the harder problem of surgical tree updates since they can't just redraw from scratch.
It's where all of their complexity comes from. Not even React's basic primitives like useState would be necessary if you were just going to redraw the whole UI on the next frame.
React is "immediate" so it probably could work. However the accessibility tools in that case operate on the rendered DOM layer. Without such a "retained" structure it would be very hard. You can imagine web accessibility tools wouldn't like it either if you rebuilt the whole DOM on every change instead of only updating the changed parts.
> but I think the “fat client” era JS-heavy frontends is on its way out
Look, you might be right! I still think it’s not the right tool for all situations. But this has been said over and over for at least ~7 maybe 8 years for what I can remember and it’s yet to be true, for better or worse. We’ll see though!
The older I get, the more I find myself gravitating toward building with Express.js, using front-end HTML with a touch of Alpine.js—and that covers 99% of my use cases. React is mostly an overkill.
On the contrary, I would say the end user's device has never been more powerful and it will continue to get better.
In real world we are supposed to use that resource(client side compute/storage) to balance the server side and client side processing, not just for performance but for optimal user experience.
This is not exactly true, or at least it's misleading. I recommend reading some Stuart Russel's articles on this or watching some of his talks.
In summary, performance is getting better on the high end, but at the same time, large parts of the world are coming online with terrible devices, so median device is not very good. P75 device is totally removed from what web developers use to develop on.
On top of that, there's still a big concern with battery life, spotty connection and apps competing over phone's resources. E.g. on Android, if your website is too heavy, the system will kill stuff running in the background. If your users watch youtube or listen to a podcast and your website make the audio glitch or kill running spotify, that's not a great experience.
Last point is that react-like sites use the phone's resources in a really bad way - phones get more cores (especially e-cores) and special processing units (ai, video, graphics) but JS runs single threaded on the UI thread, competing with everything else, together with expensive JS engine machinery. If you ever profile some SPA on some representative android device, it's just all yellow, bottlenecked on JS.
> One of the arguments for a SPA is that it provides a more reactive customer experience. I think that’s mostly debunked at this point
That's not true. You absolutely can make edge applications faster than anything running server-side. A great example is Linear, it can switch between issues within 100ms (it even supports hjkl keys for navigation!).
But this requires you to be EXTREMELY careful. In case of Linear, they're using a sync engine to replicate the data onto the client side, rather than doing the request/response model.
A few more examples of good SPAs are SoundCloud, Twitch, and YouTube. They all have the players move between interactions, which (generally) is better UX. Soundcloud in particular, if they didn't have the persistent player while browsing the site would be nearly unusable.
A triple handshake to a datacenter across the US is already ~80ms. It can be mitigated with HTTP2/3 but that still leaves you with not that much time to serve the request.
It's certainly doable, but not at all straightforward to make it reliable. A local app, on the other hand, does not depend on the network latency and the server load.
I have my issues with react but I don't think a different framework necessarily solves those issues since those issues are explicitly with how you need to handle state changes in JS and how "components" tie into that.
I haven't used it but something like Elixer Pheonix liveview[1] / .NET blazor[2] or skiplabs skip[3] or a well setup apollo client[4].
Nothing prevents you from building that abstraction on react, I don't know about Vue/Svelte.
The idea is though that there are models which should come from your backend, viewmodels which should be in your frontend code. And there should be no other state.
Whether a button is clicked or not has nothing to do with the backend. What the button does when it is clicked also has nothing to do with the backend. All that should theoretically happen when the button is clicked is you should decide what needs to happen. If a thingabob needs to be deleted from the viewmodel, no calls to.the backend. If that thingamabob is linked to the actual model then no frontend should change, the backend should change and a message that it has successded / failed should go to the frontend.
It's when you bring optimistic updates and eventual consistency etc in, then your frontend code becomes absolutely chaotic. You make it a distributed computing problem but then instead of message passing and actors which is a known good way to handle distributed computing you try to synchronise state.
Its somewhat amusing to me that in 2025, you can still find comments equating React to hype. I've been using React professionally for 10 years. Can we at least agree its not a new, hyped technology?
IMHO there's exactly two factors when it comes to having success and efficiency with established tech like React or Rails. One is familiarity, the more experience you have, the more you know it, the more you like it, the better you are going to be with it. The other is restraint. The less custom EVERYTHING you make, the easier it will be to maintain and change. If you lack one or god forbid both, you are going to have a bad time. If you have both, probably anything that's not actually bleeding edge will work out well for you.
If you don't over complicate it, React apps are very simple. Emphasis on the very. The opposite is also correct. If you DO over complicate it, React apps are extremely complicated.
Also, the SPA model works great for some apps and badly for others. This blanket ruling of "do x and not y because x worked for us and y didn't" is just bad advice.
Simplicity is relative. I wouldn't call having to reimplement basic browser features like forms simple compared to slapping Turbo on server-rendered HTML (which took me ~50 LOC last I did so on Pocket SQL).
It is. And it's very much domain dependant. One of my projects is a CRM application, which is a SPA. Years ago, I had a similar incarnation of that projects as a "traditional" html+js model. It works much much better as an SPA on many levels. It's a complex app with a lot of UI elements. A simpler application might not benefit from being an SPA. So it all depends. I'm just allergic to that style of "X is dead to me so X must be dead to you".
That's interesting because a CRM sounds like a strong use case for server-rendered HTML: Relatively low interactivity outside of form handling, which is consistently a weak point for SPAs. I wonder how different your experience would have been back then if you had modern browser APIs and something like Turbo, because the manner in which you go about the JS makes a huge difference. I would not advocate that people use HTMX for example, which strikes me as just being inline JS.
An SPA is actually very suitable for this type of app. It was simple forms in the 00s, but it's not that anymore.
First, in my case, the back end is an API (python). It is also serving mobile apps, and 3rd party integrations. Turbo is more suitable, if I'm not mistaken, for Javascript based applications.
Second, my CRM is fast. The UI is snappy and there is little lag, which is something people comment on a lot.
And third, there are many components there where a page reload will break things - for example, when you perform a telephone call from the browser. You can still navigate the data, without reloading the page and cutting the call.
It's never simple, and NEVER EVER one size fits all. I'm saying this after about 30 years of doing this job commercially.
Turbo is just a front-end library it doesn't matter what your backend stack is. You can do all of that with a MPA approach, including partial DOM updates, with just the JSON API for your mobile apps being the missing part simply due to not needing it for the browser implementation. Serializing JSON on the backend and transforming it into HTML via React should always be slower than just sending the same HTML over the wire. I'll have to benchmark Pocket SQL to get frontend numbers, but it is perceptibly instant with requests taking single-digit ms, so it's not like the server-rendering part of it is slow. I'm glad the SPA approach worked out back then! The point I'm making is that MPAs are worth another try with modern tooling.
But my personal belief is that web apps are moving towards static sites that are cache-friendly and offline-ready. This for couple of reasons, first is easy integration with CDN. Second is easy integration with webviews for mobile apps.
And easiest way to implement offlineness so far has been through a state management library. Doesn't mean that doing what the article suggests, moving logic to server, is impossible but it's quite a pain. Much easier is to move logic to client and handling it there.
Moreover, the fact there's so many UI components and libraries available for React and so forth, makes developing much faster. Depends on the developer, of course (and I personally prefer Svelte), but is a rather big advantage if you are doing anything complex in UI.
I think this varies wildly on the type of app you're building. If you are building something like CRUD interfaces obviously a server side focus is very viable and useful since you don't have to have double state management. I am thinking apps like ecommerce, banking or management software.
But if you're building a very client heavy application that does something like Photo editing, CAD, video editing etc I have a hard time seeing a server side generated content to be successful because you need a lot of client side state no matter what.
For example, I have done a lot with maps and it's not possible AFAIK to render the canvas on the server since it's a browser only api. Also I don't really see the benefit since it takes too much computational power to generate graphical things on the server.
I agree with this, it was always the case with everything in the real world as well. People use tools that can best handle the problem they have. However, I think most today's websites/apps do not require to be SPA oriented. If only the one page requires heavy client-side interaction, there's always possibility to use SPA library only on that one particular page
I agree, most websites would benefit greatly from using something like Phoenix Liveview, Hotwire, Livewire etc. That way you get all the benefits of a SPA without having to deal with the extra complexity of double state management.
I wish I was doing those kinds of apps because that tech seems wonderfully nice to work with. Unfortunately I do client heavy apps mostly so I don't have the benefit from using one. Offline support is... impossible to do good with those kinds of tools.
Im using RTK Query with React with apps where i dont control the API and just consume the JSON.
The problem with RTK Query is the strong reliance on the internal cache, which is often in the way, since i need the updated data from the server most of the time, but otherwise it works quite well.
For apps where i control the backend (mostly PHP with Laravel or Symfony), im using Inertia now, which enables me to directly access the entity/model data in the React code, without any API necessary.
This works really well and reduces the React code to the minumim, UI based stuff, where it shines.
There is a Stimulus/Turbo plugin for Symfony as well, but Im not sure if this technology isnt too niche and unproven yet, in contrast with React, which has been around a long time, has tons of docs, and also loads of devs with experience on the market.
I removed all of our React and replaced it with Web Components, and I'm not missing anything.
I'm sticking to cached static resources, and just sending data over. Not rendering from the server, but not writing single-page apps, either. The more you render from the server, the larger your caches end up. Not doing that for HTML.
Just HTML, CSS, and JavaScript. No tooling. No building. Web Components and fetch(). No frameworks on the client-side. Express still on the server.
I'm trying to optimize for not swapping out dependencies on a several year scale, and it's working out pretty well so far. I removed React because they're not interested in UMD builds anymore, and I'm not going to jump through hoops to make it work on my end, either.
Same, and I've found this works quite well with a C++ backend. Just send over binary data as struct-of-arrays, load it into typed arrays, render components. Your app will be bottlenecked only on bandwidth, as it should be, even for heavy 3d applications.
There's nothing fundamentally stopping react apps from being fast like this, but the dependency snowball has a way of hiding accumulated dynamic memory allocations and event listeners. Instead, we should be intentionally grouping allocations and events, keeping them contained to a few well understood pieces of code. Without this, these apps could be ported to native C++ or rust and they would still be nearly as slow because there is no magic language that can make a slop of millions of tiny dynamic allocations fast and low overhead.
If most data between the backend/frontend is raw numeric array binary blobs, and you target array types that can be loaded directly into JS TypedArrays (int32_t* -> Int32Array, float* -> Float32Array, etc.), you have a more or less optimal data transfer mechanism with zero dependencies. The JS parsing is faster than the fetching, even with 10s of millions of items, provided you keep the number of arrays fixed and reasonably small.
This is a natural fit for data-oriented programming in most systems languages, including C++. It's also compatible with numpy and any other dynamic language backends that have a performance-oriented array primitive or lib. The data can be served dynamically from memory, or written to files on a static server like nginx.
Is the amount of data transfer the main reason to use JSON or do you find Web Components play better with JSON payloads? I could imagine the template string being rendered on the server, fetch()-ed by the client and swapped with this.innerHTML.
Do you manage any amount of cross-component state? It's one use case where JSON would win over "HTML over the wire".
I got so sick of having to deal with thousands of dependencies with a React project, I manually implemented JSX to string components (e.g. building with ESBuild then writing the createElement and fragment functions as my own package, which would return a string to render server side), added Alpine.js, and it's just as, if not more productive than standard React.
So many fewer packages to deal with (especially if you want to SSR your app), and my site is way faster. And I get to use JSX which is my favorite templating engine and requires little porting from my React app.
I suggest people really take a look at Alpine.js, you can do everything in it as you can with React and it's a significantly smaller, simpler package that runs right in your browser.
It's more not wanting to use virtual DOM and only wanting to render to strings for SSR. For example if I use useState or onClick handlers inside the JSX template, now I'll have to handle both client and server side code at the same time, which I want to avoid. If I only render a string from my JSX templates, I can separate all client side logic to Alpine. Easier to test and less overhead.
Can you provide more details about the project you are talking about? I somehow doubt that a website like facebook would be easier to write and manage in a minimalist framework. I'm not sure the only project I have written React for would compare to something like facebook but it was a pretty complex SPA that I seriously doubt would've been better written in something like alpine.
Sure React may be overkill for a personal blog and no one is saying it isn't but I wish people that have ported from React also assess honestly the complexity of the app we're talking about
I have a website I use to host all my personal software. This includes a front end portfolio with various somewhat complicated data applications, I have a personal notes app, RSS reader, content feed algorithm, games, e-book reader, and S3 file manager. You are definitely right that complexity isn't as big in terms of number of users (for me, it's one), though I'm still making functionally complex applications.
Facebook is obviously going to have a ton of shit going on all at once, though for the vast majority of sites it's mostly just some form or another of CRUD with perhaps some somewhat complex front end UX.
You can build many web apps without React. To me the secret is with JSX, which makes everything way easier to manage.
Realistically the only issues with using a more minimalist framework instead of React is global state management and persistent components on page navigation. Global state management in Alpine can be done with Alpine.store and persistent components can be implemented with either Hotwired Turbo, Alpine AJAX, or HTMX. Are these things better than React Context/Redux and React Router/Next Router/Some other router? Probably not. But it does work.
I wouldn't recommend this approach for actual businesses, mostly because devs will already know React and thus be more productive. But I think it's genuinely a viable approach for building web apps.
> I wouldn't recommend this approach for actual businesses, mostly because devs will already know React and thus be more productive. But I think it's genuinely a viable approach for building web apps.
That's just the thing. Businesses chose a specific stack because the campaigning for that stack won out amongst any competing stack, not because that stack most closely aligned with their requirements and needs.
Boring Anecdote Time:
I do contract work. All current frameworks have a velocity for new API/endpoint creation (with DB schema modification) of between 4hrs - 8hrs (spread out over 3 - 4 PRs)[1], assuming all the PRs come back with LGTM.
My home-grown b/end framework cuts this down to between 5min - 20min (one PR only) for the same API/endpoint addition.
However, I only use my home-grown b/end stack for full webapp development, when a client wants a new system, and only when that client is not a technology company, or doesn't have an in-house development team.
That's because most businesses are using what their tech teams mandate, which IME is either Java, C# or (not as common around here) a Python or Node b/end.
Once(!) I had a dev manager agree that velocity for MVP and velocity for maintenance is a higher priority than conforming to any of the current b/end languages, which included but was not limited to C++, Java, Kotlin, Python, Node, React, Ruby, MSSQL, MySQL ... etc.
A few months later, on a call with him he expressed how fast his dev team was iterating on my stack when extending the system. Currently they are stuck on a lot of legacy that has to be extended, but they are definitely thinking about b/end in a new way now.
[1] Assuming the usual workflow of PR for ORM changes, then PR for data object layer + unit tests, then PR for domain object layer + unit tests, then PR for business logic + unit tests.
Facebook is in many ways terrible. it can be hard to work out what to do, it can be glitchy (for example updates can be slow - stuff is presumably cached and takes time to update) and its VERY hard to manage reasonably active FB groups.
Yeah sure the facebook frontend has a lot of issues and is frustrating at times but I'm not sure the random slow updates or even failures to load the page / partial info is React's fault
I don't know React very well but I used Angular in a large project and it was completely baffling to me how overly complex it was. In certain areas of the application it felt like it was completely unpredictable what value the state was going to be.
I sometimes long for the simplicity of something like Windows Forms.
I've spent my teenage years making Windows Forms applications, and the complete lack of state management isn't something I'd like to go back to.
Sure, with the knowledge I have now I could set up a whole MVC model with event based updates to form state, but at some point you're just rewriting the complex libraries that you're trying to avoid.
Good interactive state management, especially when you're tying to combine it with a stateless protocol like HTTP, is very difficult. Every complex library that's out there started off as a "simple way" of doing things.
There's nothing stopping you from doing Windows Forms applications of course, and the modern evolution of ASP.NET does look pretty inviting if you're over all that frontend crap, but don't underestimate the problem libraries like Angular solve. Microsoft tried it with Blazor, and that'll quickly get you a website that's a hundred megabytes in size because it downloads all of .NET into your browser.
By that chart, it looks like you moved that code to the server. Which is fine - I prefer the back end these days too - much easier to monitor and reason about. Especially for a cloudy app. Not so great if you are going for the offline-available featureset though.
Where did we go wrong? May be we need something different from HTML. A new spec to render user experience. Possibly same spec for Browser & Native apps across all devices.
Really hope there are more in Rails 8.1 and 9.0. More extracted tools, more defaults, higher performance. I mean we really should be aiming at p99 350ms.
We're four years into a journey that shouldn't have worked but did. I have a lot of experience with mostly server side JVM stuff and a little bit of frontend. Before 2020 that was mostly standard stuff including a largish javascript /typescript project and a bit of react.
In 2020 I took over the skeleton team of a startup. My main (junior) developer had a bit of Android and Kotlin experience; not a lot. We had no resources to get more developers. I was focusing on building the backend, which barely existed at that time so it was all new code. I picked spring boot and Kotlin for that.
We needed web and IOS apps in addition to Android and the Android app (the only thing that had been built) was a bit of a mess and honestly there wasn't much worth keeping. And with just one developer it was clear the replacement was going to be a web app. The obvious thing would have been to potty train my junior developer on react/typescript and hope that after a few months he would become a bit productive.
Instead I took a wild bet on kotlin-js. I honestly did not expect that would work. But it did. We did a brief research spike. Very successful. My junior developer did all the work. And we continued from there. I always had the plan to at some point just parachute in more developers and re-do it properly. But that never happened and nor is it needed.
Fast forward a few years, we still work with kotlin-js. Over the last four years that became more stable and better supported. It's great. It's a four year old UI code base and we're making lots of changes with confidence all the time. Kind of the gold standard for a good code base. It sure has its issues but it's under control.
Mostly I can't tell the difference whether I'm working on server or frontend code. It's all Kotlin. Kotlin multiplatform ensures we can reuse a lot of code on both. So the default place for code to go is in some multiplatform library. Which then ends up being used on both server and client.
We use a small, obscure UI framework for kotlin-js called fritz2. It emulates a lot of what react does but in a Kotlin friendly way (strongly typed, co-routines). We use tailwind for styling (after some adventures with other stuff) and are slowly converging on maybe adding daisyui to that mix (which is nice).
A lot of stuff in browsers is of course asynchronous and as it turns out, Kotlin's co-routines are awesome for that stuff. We have a lot of long running or recurring stuff happening in background co-routines. Handlers are suspend functions, etc. Integrating existing javascript frameworks is fairly straightforward. We have a few of those. Things like maplibre and a few other things.
The point here is that frontend code doesn't have to be Javascript and it doesn't have to be miserable like many Javascript projects become. Where you run your code and what language you pick for that are two independent choices. And if you have proper well designed code, it should be testable. Just because it runs in a browser is no good reason for that to stop being true.
I wouldn't recommend my choices four years ago. But at this point browsers run a lot more than just Javascript. Getting stuck with that stuff is a choice, not a necessity.
Angular apologist here. Learning curve is somewhat steep but I can be immediately productive in it and testing is built into the framework as a first-class citizen. Routing, debugging, state management, SSR, it’s all there. I like the separation of controllers, HTML, spec tests, and CSS because it allows the developer to reason about these separately. DX is damn good.
In fact I recently whipped up a front-end UI in a few days using the BAEL stack (Bootstrap Angular Electron). You still need the data layer of course, but this would be true of any UI framework unless you want to go full monolith like Rails (which I still fully believe is a superb solution).
And having done Rails, React, Angular, and a mishmash of other frameworks, libraries, and architectures, I can say that a “pure” Rails app out of the box is impressively good for most use cases, especially now with Turbo.
Unfortunately for many of the HTMX/Turbo people, they did right to identify the problem but they have the wrong solution.
The way to alleviate those issues is not to bloat the frontend with things that shouldn't be in it nor is it to fragment the code base with never ending "sprinkle" of JS.
The best solution is something like Gleam's Lustre, where you use the right tool for the job, while keeping a coherent code base:
Maybe it’s the changing interest rates or political winds, but I think the “fat client” era JS-heavy frontends is on its way out.
This is just not going to be true. It’s an AI world and we need to funnel so much high velocity text and dynamic UIs to provide a high fidelity experience.
Investing in static server rendered pages is just a surrender, the long surrender that people desperately seek from the onslaught of JavaScript.
But it won’t happen, it will either be JS or another language, but server side pages is the wrong bet.
I can't agree with the quoted sentiment either. Even I attempt to remove all my bias, most of the tools I use to work (app developer) are fat javascript clients.
Yeah. There’s been a little bit of a puritanical pursuit back out of SPA on HN (it might actually be isolated to here honestly, almost like a local band that plays in the neighborhood), but it’s an emotional over correction (imho) to the exhausting JS climate.
Nevertheless, the facts on the ground are the facts on the ground.
I was worried that an application I was building in Django, with a frontend built with Bootstrap and some LIGHT jquery was making me look like an old curmudgeon but the part about testability of the frontend really resonated with me. It was MUCH easier to structure everything as pytest unit tests and completely rely on Django for all the business logic rather than trying to put state in the frontend and deal with synchronizing states between FIVE distinct systems (remote devices, the Django application, the database, an event stream, AND the front end).
I recognize that I'm not hip or with it, because I really fell out of front end development at the peak of jQuery where it was mostly about fixing browser incompatibilities, but it's nice to see that maybe it went too far in the other direction and we're overdue for a bit of a swing back towards server side.
Just because you have an SPA doesn't mean you need any state in the frontend. Main problem with react devs is just overcomplicating and over-abstracting stuff. The best way to explain it to a backend person is like the same interpersonal problems with overengineered microservices architectures.
redux-query seems a popular library for dealing with API calls in react.
I’ve landed on a project using it.
By default it seems to maintain its own cache in the frontend of all api requests unless you use a non ergonomic feature “useLazy*” where you can give it hint if to use the local cache or not.
It’s completely terrible in a web app! Web is distributed and multi user by default.
End result with the app I’m working on if user a adds an item in one browser session, user b goes to a list view they don’t see the update, they see the redux-query cache.
It’s an over complicated mess for an already solved problem. Have the server send proper cache-control headers and let the browser deal with the caching instead of trying to build fat clients on a web app that should be thin clients.
You are right you don’t need to maintain state on the client but all these fashionable JavaScript frameworks promote doing just that.
redux-query is not popular by any means. [1]
Both react-query (that is tanstack query now) [2] and rtk-query [3] include extensive configurability regarding their caching behaviors. This includes the ability to turn off caching entirely. [4,5]
Your story sounds like a usage error, not a library issue.
[1] https://www.npmjs.com/package/redux-query
[2] https://tanstack.com/query/latest/
[3] https://redux-toolkit.js.org/rtk-query/overview
[4] https://tanstack.com/query/latest/docs/framework/react/guide...
[5] https://redux-toolkit.js.org/rtk-query/usage/cache-behavior
redux-query seems a popular library for dealing with API calls in react.
I’m having a real hard time being polite right now. Do we have an education problem because where is this person getting their information that they think redux-query is popular?
Probably he made a typo and meant react-query.
[dead]
> redux-query is not popular by any means
Yeah I don't know where the parent comment got this from. Every few weeks I seem to see these low effort posts that basically boil down to "javascript bad", but gets a lot of upvotes. And when you read into it, you see the author often has a poor grasp of js, or its ecosystem, and has set up some unholy abstraction, assuming that's how everyone does it.
Use the right tool for the job lol.
That sounds like an application architecture problem, not problem with react or redux-query.
It is an application problem, agreed.
It’s an application problem caused as a result of choosing the library, a common recommended library, and how the library and its documentation promotes its usage. The tools used were as the tools recommend. Admittedly, joining the project the wrong tools for the job were selected but these are all the react standard supporting libs.
The application should have been architected not to use redux-query, instead use the browser fetchApi and server side cache control headers as we own the entire stack. Today that’s controversial as ”every body uses” and “this is what the docs recommends”
Well, these libraries are doing something inherently complicated on top of just using browser cache headers.
You're only talking about http endpoint caching. These solutions are providing application data caching. These are not mutually exclusive concepts.
The latter offers things like data sharing/normalization across endpoints, data persistence across browser sessions, fine-grained cache invalidation/manipulation, and a lot of things on top of that.
It's a lot harder to manage a cache, and for most apps I never found it worthwhile. But there may be cases where you do want that level of control, like PWAs or an app optimized to never hit the network unnecessarily.
But it's definitely not replaceable with browser http header caching.
Serverside rendering is apparently a new technology now. And this brand new thing called islands which someone reinvented recently.
It's back, but the nice thing is it's 10x more complicated now!
[dead]
And in slow javashit!
So, an overall win for software developers and cloud providers?
Oh no. So Java JSF was right after all? :-)
No, the only project I've worked on that was a massive failure was built with Java JSF.
Salesforce's visualforce pages are JSF though
Yep, time to dust off PrimeFaces.
>Yep, time to dust off PrimeFaces.
You joke, but PrimeReact and PrimeVue are some of the best libs out there today, due largely to that heritage. Great company.
Sure, it has always been the best JSF framework.
PrimeFaces is very well-maintained and regularly updated.
I'd even go further and say that it's one of the few things that makes working with JSF bearable for me.
I'm still a thousand times more productive with React though, and PrimeReact also helps there.
What are islands? The new servlets?
Smallish parts of JS (React, Vue, ...) sprinkled into your website for interactivity. I use it with AstroJS: https://docs.astro.build/en/concepts/islands/
I straddle the fence here, I think we jump down people's throats a bit too quickly when it comes to putting names on their new library. But I do also wish we'd stop reinventing things and patting ourselves on the back in other cases.
Eg we are definitely working backwards from SPAs now. "JavaScript islands" were how we got to SPA frameworks in the first place.
I don't have all the history and references, but anyone working in web in the late 2000s and 2010s can attest to how progressively adding in javascript on server side rendered HTML was already happening, even componentizing the server side code with CSS and JS packaged up was very common.
"The term “component island” was first coined by Etsy’s frontend architect Katie Sylor-Miller in 2019. This idea was then expanded on and documented in this post by Preact creator Jason Miller on August 11, 2020."
My only gripe, is that this leads the ready on an alternate history of how we got here.
The general idea of an “Islands” architecture is deceptively simple: render HTML pages on the server, and inject placeholders or slots around highly dynamic regions […] that can then be “hydrated” on the client into small self-contained widgets, reusing their server-rendered initial HTML.
cryogenic lab tech: Welcome to the world of tomorrow!
portlets
Portlets! I see I'm not the only member here of this exclusive club.
I started out using React in "islands" almost 10 years ago. The server rendered page would have React components attached to the interactive parts of the page. Fascinating that we're coming full circle to that. Hopefully with better state management and interoperability.
Using a SPA doesn't mean ignoring software engineering principles.
At my work we develop web applications for a mission critical sector (emergency services). We use .net for the backend (we have also used golang in some projects) and Typescript and Angular for the frontend. We follow MVVP patterns, SOLID principles, etc. There are multiple layers, each layer has a well defined single responsibility. Our applications have been quite successful with happy users and great maintainability if I may say so.
There is nothing special about our setup. We could have used Vue.js or react for the frontend. We could have used any platform to build REST endpoints (though personally I like strongly typed languages for implementing business logic and think .net is underrated).
Software engineering might not be as old as say civil engineering, but we've been doing it for decades now and have a rich library of patterns and architecture types to draw from. I've been building software for over 25 years; the technology stack might have changed in that time but the principles are still very much the same or are extensions of the previous ones.
Using a SPA doesn't change the fact that if you want to build good applications, you first have to design them.
> Let’s assume that making a JS change costs twice as much time a Ruby change, which I think is being generous to JS.
Everyone's mileage varies, of course, but this is quite the assumption. It feels like a lack of familiarity/comfort with the frontend or poor tooling.
With typescript and a basic UI library like MUI, this really shouldn't be the case for UI changes. If you're using raw JS and manipulating the DOM, maybe?
The original post could have been a bit more precise on this point. Basically, this math assumes something where the server-provided data changes in concert with the frontend.
If we're using jsonapi, GraphQL, Thrift, or any other protocol that's not HTML, we need to do the following:
- Make the change on the server to support the new functionality. Deploy.
- Make the change on the client to adopt the new functionality. Deploy.
- Remove the old functionality from the server (optional)
Because the client is a separate application, it becomes riskier to deploy those changes together. I need to think about it more as a developer.
With server-authored HTML, this separate client + server deploy is not required.
There are a couple of reasons this is not convincing either:
- Other factors can often dwarf the separate deployment overhead, especially given that the deployment steps are done so often it will force the team to make it efficient and get used to it.
- There is no hard requirement for separate deployment in the first place, if we are just talking about react / spa you can deploy it in a single step. (Not saying you should)
The point is: yes there is quite a lot of overhead. From separate deployments, from separate state management and I think the big ones are often having two different programming languages and having to align schema on frontend and backend. It is hard to deny this. But then saying that because of this overhead, these kinds of apps take 2x time to code implies denying there are benefits as well, that under given circumstances can outweigh the overhead.
I think it is more interesting to assume that in some cases the benefits outweigh the cost of the overhead, and in others they do not.
>With server-authored HTML, this separate client + server deploy is not required.
SSR has been a thing in react for a long time.
If the app has a backend, aren't we still talking about modifying two distinct apps (React + backend app) vs a single one?
Obviously unless the team has committed to React SSR + React backend (is this common?)
Not necessarily. Most of Rails+React apps I have worked on have had the frontend code live in the same repository, and get deployed during the same step.
Yes, you have to keep API compatibility in mind when doing changes, because long-lived sessions might still exist. But has not been that much of a big deal in my experience.
Not necessarily. We write Typescript for front and back ends, using statically rendered SolidJs, skipping SSR, and hosting the corresponding Typescript in Lambdas.
Would love to hear more about the deployment for that.
CDK BucketDeployment to S3 fronted by CloudFront using a simple CloudFront function that redirects all paths to the index (main entry) file.
`aws s3 sync` could have been fine.
Was that the piece of deployment you were curious about? If not feel free to be more specific.
It sounded like your app includes Lambdas as well? I assume there is another deployment pipeline for those?
Thanks!
Yes, we use Lambdas but the CICD pipeline is shared and currently deploys everything everywhere every time though it will be more efficient to detect and only deploy deltas (there are some minor out-of-the-box detections of non-change but further optimization is very easily possible). For now, it's more important to pursue product market fit - the deploy is ~4 min per environment which is plenty good for current purposes and could easily be parallelized among other obvious and easy wins.
OVERALL: I recommend the Serverless Framework but SSO wasn't supported at the time I started building so we use the CDK for deploying everything. The CDK stacks for the S3 bucket (etc.) and API are separate but that's a matter of factoring for clarity since it would be fine to have one big stack. For similar reasons, I factor the API and API deployment separately, alongside the WWW and WWW deployments. The entire company is a monorepo with a single command at the root that, beyond one-time account bootstrapping (which also uses CloudFormation and CDK), triggers scripts run locally or remotely to execute unit testing, deployment, and acceptance testing in a progressive multi-account deployment (on main). The CICD script installs dependencies, runs tests, identifies itself and uses that to assume account specific roles to deploy into the individual environments. This is all pretty excessive for a startup but seemed like a worthwhile and more secure foundation for actually trustworthy experimentation in delivering solutions into some of people's most sensitive private spaces and visions to go deeper.
Meta-note: I accept that the separated pieces of the infrastructure have timing deltas and that some bugs could arise out of this once we've scaled. This is never not a problem but can have diminishing windows and/or effects with investment. This can be solved either by coding the API to handle current and current-1 contracts or maintaining concurrent current and current-1 lambda version deployments, where divergence occurs. None of that contradicts a single deployment of consistent code. There are deeper solutions with greater financial efficiency but I'll need a wild success scenario before those make business sense to invest in (monoimage k8s, knative, and so on).
LAMBDA: we have built configuration that specifies the build entry points for tree shaking so that our deploy sizes are tiny and that is used by the CDK pipeline too. Our data tables are declared there too so that code and deploy share config. The Lambdas are grouped by event type (i.e. HTTP/ApiGateway, S3, Kinesis, EventBridge, etc.) and our declarations are structured according to generic Lambda defaults, a source-event-specific defaults, and a function specific declaration, allowing overrides at every level. This may sound complicated but it very cleanly organizes the configuration rather compactly, providing incredible clarity, and making scope of effect explicit and consistent.
Everything is written in TypeScript which covers internal compile-time type safety but I have written a layer of middleware for the Lambdas so that they declare their contracts (that uses AJV to validate schema to type equivalence [JSON Schema is far more specific of course]) and entry points and enforces schema compliance (engineering requirements) at all boundaries in and out of the code base (i.e. receipt of API calls in client, receipt of client requests to API, S3 data, database puts/receipts, and so on).
This got long so feel welcome to reach out (see profile) if you want more specific detail about any specific piece.
The fashionable thing for a while now has been to write your react webapp as a single app. Here is one example of a "fullstack" react template: https://create.t3.gg/
Interesting setup. Looks like getting to a zen state like this would have required them to migrate their backend from Rails to ts at some point. I can understand the engineering decision not to do that.
yeah and it sort of sucks in comparison to most other server-authored HTML solutions, in this statement I am of course thinking of Next but I suppose various forms of suckage will be found in other solutions.
And to me both suck, compared to traditional template rendering like Jinja2 or Django Templates and those suck compared to SXML. React because of JSX and NextJS because of JSX and its assumptions about directory/file structure mapping to request routes, unless you change routing. JSX templates have that same feel, that PHP has from back in the day. Treating HTML as a string, implementing a wannabe HTML, that is not actually HTML, but slightly differen (for example the class attribute of HTML elements, or Fragment, <>) and enabling people to put JS logic inside the that string, mixing everything again, requiring to have a separate parser.
Separate parser is basically what Jinja2 has or other templating engines like Django templates. React could have used any templating engine that already existed.
But compare it to the elegance of SXML and treating HTML as the tree that is it, as structured data, enabling pattern matching on that, avoiding the need for a parser, and all other things that are in the language. Use. Structured. Data. It is so simple.
Mainstream frameworks got a lot to learn still. They are still on the Kindergarden level of treating HTML as a mere string for most parts.
Absolutely, this is one of the main assumptions where the blog falls apart. What takes more time and carries more risk, really depends on context. Boring, but unavoidable. This is another one:
> when compared to a world where that change isn’t risky (server-rendered ERB)
Server rendered html templates a la PHP - which is what ERB is, may be not risky in this smallish project with likely a fairly straightforward UX and seasoned rails devs, but it can be risky in others for sure. I think a lot of the motivation to embrace what react began was a desire to move out of a tangled mess of spaghetti templates, to be able to use means of abstraction and modularity as powerful as regular backend code. Frontend devs want to create and use components. You cannot create a component with html templates, not really. It will be a mess.
Moving from server rendered html to an api + spa architecture has quite an overhead of course. Just like adding a separate backend service. That price should be worth it. And a good developer can judge whether in which context that is the case. But pretending the benefits that motivate such a change just never justify the costs doesn't make sense to me.
The cost of a change is a very, very complex measure. Anyone who has a simple answer to it that is universal, true and useful will win a Nobel Prize. This is because the cost depends on the person who is making it and his peers, on its effects in the future, on the project of which it is a part, on luck and on the larger ecosystem in which it is done. There are just way too many parameters.
My experience with very highly paid frontend developers is they like to spend hours and hours (and thousands and thousands of dollars) building out little libraries and components and frameworks that will enable other teams to be faster. Except this never eventuates because things rarely turn out to be reusable along the right axis so a new component or library or framework is developed to solve the problem.
On top of this UI developer propellor-heads love to spend time (and money) pontificating on abstract theories about functional programming and homomorphisms and endofunctors so they can render some text inside a <b> tag. It's how we wound up with utterly ridiculous pieces of code like the "hooks" API in React.
Can’t get promoted pumping out 10 great pages. But a library that you can claim will enhance the productivity of 100 other engineers? Now that’s IMPACT!!
Except you’re at a company where everyone has figured this out so now you have 4 competing libraries with their own teams which are all 1/2 done making every engineer less productive cause they all have bugs and slightly different priorities.
this is exactly the frontend team from a previous role. we were losing millions a month and had 2 major cuts within 4 months - and instead of cleaning up or simplifying our bloated frontend, the teams responsible for it started building new component libraries for the rest of the org to use on future pages
4 competing in-house libs? How can that ever happen? Is middle management non-existant? That is anarchy, hehe
I also get the feeling that modern frontend is a massive money pit but this seems to be a leadership problem. I wouldn't go so far as to blame the IC. There are developers over-engineering in every ecosystem.
Something about the psychology of front-end - not quite as hardcore technical, a little more humanities-aligned - perhaps makes them even more susceptible.
The self-consciously cool kids are always going to be more easily swayed by fashion than cave hermits.
You forgot the part where everything has to be redone every 5-10 years despite grand allusions of reusability because of the cyclic nature of the frontend market. The JS framework proliferation is largely driven by skills becoming obsolete (or needing to become obsolete for economic reasons) as younger frontend devs move in who want to carve their niche and distance themselves from "horrible" previous-gen unmaintainable and wayyy overengineered stuff. Which was objectively unmaintainable either from the start as a work of love of a developer who put all his thoughts into it so it became incomprehensible ;) or became unmaintainable when later developers (who couldn't care less) had to violate the original grand vision of state encapsulation or hypermedia architecture or whatever for a trivial business form app.
I guess the good thing is that comprehending our absurd web frontend creations is beyond current LLM's capabilities.
I've done a lot of back-end and a bit of front end development. You're correctly identifying a crappy outcome, but incorrectly attributing the effect of shitty developers and project management with whole disciplines and common practices within them.
I've had exactly the same experience.
I think the author was talking about React specifically.
I've worked in JS, TS, React, and RoR, and yeah I'd say making a change is probably twice as quick in RoR as in React.
The thing is that Rails is an opinionated framework. If you do things that the framework is designed to do, then it's very very easy. If you go off-piste and have to fight the framework to do the thing you want it to do, it gets very hard very quickly.
React is less opinionated (about most things) so the converse is true; it is slower to write stuff in, but there's less constraint.
I feel the comparison is really hard. Rails really is a framework that solves anything but the business logic for 80% of your app. React is really a library for rendering components and everything else is your decision to pick or build from scratch. E.g. Rails has opinions on how to build forms while React, a supposed frontend framework, doesn't have anything baked in specific to that. Sure the community has opinions about it but React doesn't like Rails does.
There is no free lunch though. Typescript and whatever frontend stack we might go with will come with their own drawback. It doesn't mean the trade-off is never worth it, but we better keep in mind that adding transpilers and a truckload of external libraries does have a maintenance cost.
Typescript has so vast productivity benefits there is no any second though to use or not to use it.
I wouldn't touch a React project without Typescript. But if you use something like Web Components (or Stimulus etc) where you compartmentalize small bits of UI into distinct reusable components, JSDoc gets you 90% of the benefit of Typescript without the baggage.
Also it depends from API response. It could vary from FE dictating schema or backend making hard orthogonal domain modeling API.
In first case FE is productive there is no need to transform data but makes BE a hot mess. Otherwise FE have to maintain layer of code to convert BE data to presentable UI data. It's harder but allows to decouple UI reqs from changes along all stack.
Yeah this seems like an insane assumption on a language basis. Ruby has no static types (or not very good ones as far as I know) and is very hard to follow due to using "magic" so much.
I've contributed several features to VSCode (Typescript) and it was relatively easy. I have completely failed to do the same with Gitlab (Ruby) because the code is so hard to navigate. I did manage to add some features to gitlab-runner but that is written in Go, which again is much easier to follow than Ruby.
I think they are really talking about client-side vs server-side rendering. Server-side is much simpler.
[flagged]
FYI - There's some neat ways you can embed React components inside Rails templates. Basically - embed the props in a template-managed `script` tag, and use Stimulus to mount the react code, passing in the props read from the DOM. Now your React is pure state-to-view, no need to synchronize anything, - it's really just a handful of React components instead of a full React app.
That said, AFAICT, there's just two advantages:
1. Those annoying little UX doohickeys that actually DO want that level of interactivity
2. You can use any of the vast library of existing React components (for me, that's been react_big_calendar)
As a bonus (and, why I rolled my own, since `react_on_rails` doesn't support these), and with a bit of tweaking:
1. It plays nicely with Turbo. I can use Turbo to update my React props and it just... works.
2. You can embed a template as a child of the React component.
2a. This also plays nice with Turbo.
It sounds a little screwy, but so far it's working well, and it feels like it lets me use the right tool for the right job - aka, Rails for everything except the stuff with extremely high interactivity.
Amazing! I would love to see a blog post or a gem that unlocks React components with a Rails + Stimulus/Turbo app.
https://evilmartians.com/chronicles/the-art-of-turbo-mount-h...
I intend to! And to wrap it in a gem; I’ve got it partly there, but it’s a currently a mess as I ran into a bunch of “oh that didn’t actually work” problems at various points. I’ll post a link later…
Edit: Ach, sorry - it's going to be awhile, when I went to roll my own I did it inside my project, so it's not even close to being available as a gem :/
I do this too, it works well
HN is not real world, just like how Reddit is not real world.
I am a FE with 10 years of experience, and has tried, and tried really really hard and multiple attempts to make HTMX works well.
Doesn’t work. UX is much worse, code discoverability is much worse, slower to code in, everything is messier than just plain React SPA with JSON data. Terrible, terrible DX and UX.
Seriously, there is a reason why despite all the rage in going back to multi page Django/Rails app, very very few people actually take it seriously. You just don’t hear the negativity because most folks just tried it, saw that it is worse, and moved on without writing a blog post.
I've contributed to all kinds of frontend setups; Elixir LiveView, React, Vue, Angular, HTMX and many more.
I've yet to find a frontend scripting solution that works well. My current stance is to have the frontend as thin as possible, no matter how it is written. Have your domain logic on the server output Plain-Old Data structures (JSON or similar) and render them with stateless, dumb views, be it a template, Vue, React or whatever.
A clear boundary between the domain logic and view is important. Rails templates that can basically access anything is a terrible idea.
I have similar kind of experience and made similar conclusions for myself.
In addition to the points you have made already, I would like to add that almost every larger project needs a lot of business logic on the backend side anyways. There is no possibility to have this logic in the frontend and there never will be (for security reasons at least). So given these circumstances, we usually already have quite a few people experienced with - and very efficient in - these backend technologies.
So why would I spend a lot of time re-creating all kinds of routing, models, properties, etc. in an SPA? We currently run an Ember SPA for our largest project and 1/3+ of the time spent on it is pure waste because it is simply additional work to facilitate the use of this SPA at all.
In every project I've worked on, the interactive and dynamic elements actually used that are written in JS end up being a lot fewer than originally anticipated. Unless you're building a product where the majority of the functionality relies on instant, realtime updates such as maybe a streaming site with chat, etc., building, maintaining and extending an SPA is a huge overhead that offers little benefit over "dumb", static views with small, isolated interactive components.
> Unless you're building a product where the majority of the functionality relies on
This is a huge problem in the ecosystem. People want a landing page, so they reach for some full-stack SPA backend+frontend framework that is hip today, which is absolutely bananas.
Sure, if you're building web app with lots of dynamic and interactive elements, go crazy, because you'll probably need it, lord knows you'll get tangled up in state management no matter how clever you think you are.
But for websites that aren't trying to became the new Google Maps/Figma/Whatever, simple and basic templating patterns won't just be faster to develop, but easier to maintain and a better experience for your visitors to use.
My experience exactly. Why one would do that anyway? Not listening to experienced engineers and being blinded by modern FE hype. Thinking just because many other businesses do it, one has to do it too. Then decision made by non-technical or not too technical management people.
And sure enough, then came the self inflicted workload. "Oh we need to change the router.". A problem you do not have with any popular mature web framework on the backend. "We need to upgrade to NextJS version 149, for feature blablub." Which would come naturally with something like Django or other traditional web framework. "We need to upgrade NodeJS!" ... and so on and on.
While all of what the FE actually did could have been just render static templates and a few lines of script.
Companies choose their own downfall by following the FE hype trains. The result are the shitty web apps, that don't need to be "apps" in the first place, but could simply have been static pages. It is quite a comedy show and I would laugh, if it did not affect me negatively.
I also have a lot of experience with various setups and front-end technologies, and I couldn't agree more!
Furthermore, I'd say this: if you can't simply serialize your view-model and send it to the client because something might get exposed or because it's a complex object with embedded logic, your first priority should be fixing that. Only after achieving this should you even think about changing how you handle the front-end.
We use inertia.js to do exactly this.
It's a really strong selling point that you can use a popular FE framework for all the templates, but at the same time almost completely avoid state management.
> but at the same time almost completely avoid state management
Unless you're just building simple landing pages (I think the context is "web apps" here) or something, you might not have removed any state management, you've just moved it elsewhere.
So the question is, where did you move it instead? The backend?
That is a good point, and I can see that I probably did not communicate what I meant clearly enough.
In my experience most of the state management in FE apps is about fetching and handling data from different types of APIs. With inertia you get a very simple abstraction in that each page gets its own little API. Then inertia takes care of feeding the data from that API to the rendered page when you navigate to it.
For that reason the page can be a "dumb" component, and there really isn't much state to manage.
If the app needs modals, dropdowns, forms e.g., you will need to manage the state of those in the browser, which I think is very reasonable.
Obviously there can also be situations where you'd want to have a small part of the page to fetch some data asynchronously, and for those you'd need to use something else - inertia doesn't do everything.
Out of curiosity, what difficulties have you faced with Elixir LiveView? I am developing in it right now, and am enjoying managing state and interactivity in one codebase (I like how everything is channeled through the socket).
Has your experience been more negative?
My primary complaint is that it is hard to test (compared to "stateless" pages) and that the whole thing feels complicated.
I also feel like the learning curve is pretty steep and you can't just have a random, experienced non-Elixir dev join the project and have them fix something. They must be comfortable with Elixir & Phoenix before they get productive. I feel like it is multiple layers of complexity and uncommon patterns.
Other than that, I think it is very cool. I have very strong mixed feelings about the feature hah.
If you handle all interactivity server side so that the user can’t do anything at all without a round trip, sure. It’s just a terrible app for users with latency/patchy connectivity. As soon as you try to mix in slightly nontrivial client local state and transforms it becomes the most retarded JS imaginable.
This is the common misconception of LiveView coming from the JS community. LiveView is JS. It has a whole optimistic UI layer that solves all of the problems you cite. The UI from state updates coming from the server or the client doesn't matter because the reactive UIs of SPAs still require data updates from some remote source. So if we're talking about latency that latency is going to exist for all application types.
Where did I say it’s not JS? I said it becomes the most retarded JS imaginable. I have used the “whole optimistic UI layer”, hooks and commands. What happens is local diffs have to fight server sent diffs, at every level, resulting in more tangled logic than jQuery apps. This does not happen when you merely have to merge state and the view is a pure function of state.
Can you offer some examples of issues that have arisen from using the rails-style template with access approach?
It is very easy to have very important choices made inside a rails template, like permissions (can X access Y?) and it is similarly easy to ignore permission checks and just query anything you like.
This makes it also very easy to end up with N+1 issues that are not caught in tests (because the tests don't render views), "forgetting" to scope the data (rendering more records than the user should be able to access) or rendering sensitive attributes the user should not have access to.
Even with tests that do include rendering the views, it is very easy to have a test like:
Now there's so much wrong with this test, but the primary issue is when the view does something like this: The test implies the document should only render the current user's posts, but the view / template actually renders all posts. You don't want to test this kind of logic by inspecting HTML, because it is error-prone and expensive to test this way.What if you want to change the HTML structure? You'll end up rewriting all these tests, and it is VERY EASY to make subtle mistakes when rewriting the tests, resulting in false positives in the future.
Instead, I think you should separate this logic to a model, not to be confused with "activerecord classes" - I'm thinking of a `UserPosts` model, like this:
Then you also disable automatic loading of relations (forgot the config name) and, by convention (or enforced in some way), never refer to any model modules or classes in a view (or any method called by the view, like the helpers).Your controller will likely look like this:
By keeping the domain logic inside specialized modules per access scope (i'd have separate `Posts`, `PublicPosts`, `AdminPosts`, `ModeratorPosts` modules), you can test the logic in tests per module (including tests what the module SHOULD NOT access). Then, when writing the views and controllers, you don't need to re-test or re-remember to test the "should not" cases - the test cases you're easy to forget.You can also design the modules in a way that they only load (select) the properties that context would be allowed to access. If you have sensitive data (like a user's real name or email), you don't even want to load that property when loading the users from a `PublicPosts` context, since public posts should only render the user's id and public nickname for example. You can also wrap the posts/users in presenters using whatever fancy gems you fancy, as long as it gets the job done.
In an ideal world, I'd lock down Ruby templates to only have access to previously loaded data via instance variables and helpers, nothing else.
It is a bit hard to explain, since I have limited time to address it properly, but I hope I get the point across.
I'm a freelance webdev with 15 years of experience, and recently I've made some new projects with Symfony Stimulus & Turbo to great success.
A few thoughts:
I tried just htmx too, too limiting. Stimulus/Turbo combination is much better.
Use the right tool for the job. Highly interactive app, like an editor? Use react or similar js framework. Mostly page/document website? A backend framework is much faster and easier to develop, and much simpler to test.
Use what you know yada yada.
A blend of both? Drop in a React component where needed on a given page! People forget (me included) that even React can be mounted into a single DOM element.
With all this framework nonsense its hard to forget at the end of the days its all just javascript.
If you're doing something something reasonably small, using preact rather than react and then wrapping it into a web component so you can just ... put it in there ... is a really nice option to have.
(it may not be the right option in any given case, but it's worth knowing it's there even so)
Preact is definitely a good choice if you're looking for something lightweight. React-dom was already relatively hefty, and seems to have gotten even larger in version 19. Upgrading the React TypeScript Vite starter template from 18 to 19 increases the bundle size from 144kB to 186kB on my machine [1][2]. They've also packaged it in a way that's hard to analyze with sites like bundlephobia.com and pkg-size.dev.
[1] https://github.com/facebook/react/issues/27824
[2] https://github.com/facebook/react/issues/29913
I'm not too sure about HTMX in particular, but my Rails app's FE is just HTML and Stimulus/Turbo. I'm not sure why you think it simply "doesn't work".
To me, it's a lot simpler. I use forms and links and render HTML templates. That's it.
I don't need to worry about building and maintaining a JSON API just to serve the front-end. I don't need to worry about distinct sets of routes and models. There's just one repo with one build pipeline and test setup. There's no need to worry about front-end state at all, since I'm just using plain-old links and forms.
I'm not claiming that there is never a use for React or its ilk, but I am genuinely finding it hard to understand how one can assert that this simple HTML-based approach is categorically worse in all circumstances.
In my context, the simple approach works. If I were working on something that had a high degree of inherent complexity on the front-end -- maybe a web-based video editor or some kind of WSIWYG productivity tool -- this approach would almost surely fall apart, but that's the point of engineering: Choosing the right tool for the job at hand.
The truth is in a similar vein but more general - most just pick the stack they are most productive in, whatever that may be, and move on without writing a blog post.
For less frustration when reading such posts that are written, read the author as writing for themselves, reporting the pros and cons for their very particular situation, and see if there's some nuggets to be found in that context.
Don't read them as telling you those same pros and cons apply to your situation -- even if they veer into implying they may :-)
> Doesn’t work.
It worked for us, one of the most visited websites in my country, migrating away from a Vue.js based “modern” frontend stack.
It was a huge success in terms of productivity, developer experience, and cost.
This may depend on a type of website/webapp one is working on? I have a suspicion that sometimes HTMX may actually fit nicely (e.g., for an online survey), sometimes React-like framework is the probable way to go (e.g. a marketplace app), and sometimes it could be that neither is a good option (e.g. games).
The main problem is that it is not really viable to start with HTMX and add react (or another frontend framework) later because you end up having two completely separate stacks that are very incompatible with each other.
The worst sin a large codebase can do is being inconsistent.
Ah yes. The You Are Maybe Gonna Need It (YAMGNI) principle, a classic.
Unfortunately yes, because you often do need it.
suppose it depends (https://htmx.org/essays/when-to-use-hypermedia/) but i see an awful lot of apps choosing SPA frameworks to just move forms into databases
If I understood correctly the author of original post is also talking from real world experience, not running university research lab.
The Web development projects I work on, are still mostly server side rendering for the last two decades, using Java and .NET frameworks.
And when not, it is due to CMS products available as SaaS like contentful.
In such cases we go for Next.js due to it providing a similar experience with server side rendering and controllers.
In one thing you are right, we don't take seriously development stacks that don't offer either JIT or AOT compilation.
>>> You just don’t hear the negativity because most folks just tried it, saw that it is worse, and moved on without writing a blog post.
How does your approach contribute to the discussion? You created a new handle named ‘htmxsucks’ solely for the purpose of making this comment! While it’s perfectly acceptable to express negative opinions about a technology and be vocal about them, doing so anonymously in this manner undermines your credibility.
I too, am someone who creates a new handle for every single comment, and I would like to point out you too lack any meaningful point aside from that personal observation. Yes, it is cowardly, and I agree with the sentiment of being forthcoming with identity when making negative statements related to your field. It's actually less isolating, despite one's fearful assumption. But that is still, regardless, a point completely unrelated to the actual "discussion" you're putting on the pedestal.
So now we have two posts derailing this.
I’m genuinely impressed that you took the time to create a handle based on my name, replacing “me” with “you”! I’m upvoting you for this thoughtful gesture!
Check out Datastar (https://data-star.dev) . It's similar to htmx, but far more powerful AND simpler.
I have a side project that was using Vue, not even React, and every time I went back to it, it was hours of bringing everything "up to date". Everything seemed antiquated every few months I'd go back to it. It never moved past the blank landing page.
Then I moved to HTMX and I did more in 5 weeks than I did in 5 years.
> it was hours of bringing everything "up to date"
Why? We still have Vue 2.6 (not even 2.7 with compAPI) projects living and chugging along just fine. Why do you feel the need to keep everything updated to latest or whatever?
Because no one wants to work on an open-source project that uses fossilized versions of libraries.
Don’t let perfect be the enemy of good. They certainly can’t work on it if it doesn’t exist.
I think only people who follow frontend hype don't take traditional web frameworks seriously, especially some as mature as Django or Rails.
It may be, that very few people these days actually know how to make a website without reaching for hyped JS frameworks. The thing is, one needs to know more than just JS. One needs to know an actual backend language and learn the framework. Many web developers these days don't have this set of skills, might not even know another language than JS, even though it is not hard to learn.
Not every website needs to be a "web app". Not every website needs to be some SPA. Many are better off without being an SPA. Once you are not building an SPA, many other frameworks become very viable and proven alternatives, among them Django and Rails.
Can you share an example of a large react SPA that you would consider a good UX? One that doesn't have that react, not very reactive feeling, jank?
May I add to this the requirement to actually be able to use standard browser functionality like back button and open links in new tabs?
This should exclude roughly 98% of React SPA websites, which ended up being shoddy-made, non accessible.
Also underappreciated thing is the community. For any decent/widely used framework, the architecture or other aspect is good enough for your usecase. It's unlikely that you would get significant gain due to the framework for all usecase, but having a community where every question you could possibly have is in github issues is very useful.
Im a gen z and the best experiences were with Angular and React. Sure, it's not always pretty, but I'd much rather have a framework that pushes me in the right direction. If I had to use HTMX for work, then I would've guaranteed used it wrong. It's just not worth the reviews and hassle if the result is less standardized. It's also harder to find HTMX dev's when there's so much React devs (or devs willing to try React, seriously if you've worked with one CSFW then React is child's play)
> If I had to use HTMX for work, then I would've guaranteed used it wrong.
As someone who's been doing web dev since the 90's and is currently leading a project that's built with HTMX and having onboarded a few younger/junior "react devs", you're not wrong. What I've seen is that there's a whole generation now who just don't know how to do things in a different way than by building a SPA. The difficulty onboarding those devs is always in getting them to unlearn the patterns that React/Angular/etc. have ingrained in them. I've reviewed PRs that were a mess of complicated HTMX attributes, backend logic switching on headers, etc. and pointed out that all of it could be replaced by just, like, using a plain old HTML form submit or `<a href="..."`. I wish I were kidding. They almost always start out massively overusing HTMX out of a fear of triggering the dreaded full page reload. But in a non-SPA world, with a fast backend, full page reloads take milliseconds because there aren't MBs of JS to download and execute and a bunch of client-side state to reconstruct.
> It's also harder to find HTMX dev's when there's so much React devs
For someone who is familiar with basic web technology (like the 20 year old version with HTTTP/HTML and minimal JS/CSS), it only takes 15 minutes or so to learn HTMX (then maybe a few days of building where you pull up the docs occasionally to remember the names of the attributes). The idea of someone calling themselves an "HTMX dev" the same way we have "React devs" is ridiculous.
As someone who hasn’t touched fe dev since vue alpha… I chose next, then remix. Then moved to svelte before I went too deep. The application I am writing could easily be done in django or .net with some simple js - but with svelte it all ties together so easily. I guess I could accomplish similar with partial views or jinja2 templates.
> It's just not worth the reviews and hassle if the result is less standardized.
I'm pretty sure HTMX is closer to standard stuff than anything you do in Angular or React.
Can you say more about what didn't work with HTMX? What parts make terrible DX?
I also think HTMX is meant mostly for backend developers to be more productive in frontend.
My experience with it is, one there’s no decent templater for nodejs, two this web1 like architecture really makes no sense as a developer. Everything is a subpage transfer rather than a meaningful operation/update. I came from desktop ui background (delphi, vb, gtk, qt, appkit), not from web. The web is all fucked up, tbh, it’s not only htmx. But at least spas vaguely resemble how normal apps function.
I see. HTMX and others target the browser, which is primarily an HTML renderer. So there is nothing inherently bad about page transfers. That's what hypermedia is about.
React et al try to create a different paradigm on top of this. And that makes it like building a desktop UI AND a server app
To me, this is not in anyway better than building something for the browser - pages and html.
> HTMX works well
Yes, this is a fact. HTMX / Unpoly are just lighter solutions and much easier to debug.
I am surprised that Unpoly (https://unpoly.com/) doesn't have the same recognition as htmx/stimulus. I blame the obtuse project name.
Wish the web spec just standardized a mechanism for partial page load/render. It would become the most frequently used developer technology feature of the 22nd century.
Agree. Self-plug; Posted about the same hype I see with liveview on Phoenix https://dnlytras.com/blog/on-liveview
Maybe the problem is that as an FE developer you are better at doing things in the front end?
The original reason the web took off to dominate the internet was because it had a very, very simple UI.
I am starting a new web application frontend project soon calling a backend REST api. What would you recommend in 2025? I don't have legacy requirements. React? Vue? Something else?
Use the framework that has the libraries you need, React has a lot of ecosystem around it so it tends to have everything. You don't want to spend time integrating a plain JS calendar library into your random framework when you can just use react-calendar.
So look at your requirements, check the framework for libraries and tools (like deployment, hosting, monitoring etc) available. The libraries you use are much more important than the framework.
Do note that although there are plenty of react chart libraries they tend to be quite under-performant. Tying chart rendering with any frontend framework building blocks ends up with bad performance. If you are dealing with >10k data-points that update often I recommend using a plain-js chart library.
Which framework-specific libraries do you even need? It’s UI, like forms and buttons and inputs and tables. I can’t imagine e.g. choosing between GTKmm and Qt over “libraries that I need”.
deployment, hosting, monitoring etc
Isn’t this backend-related? Generally framework agnostic?
Deployment and hosting is just publishing a Vite/etc bundle, right? What is framework-specific frontend monitoring?
> It’s UI, like forms and buttons and inputs and tables
For the most part yes, until you have a very specific requirement like complex drag and drop interactions or a complicated UI component like a calendar view. Also don't underestimate how much work it is to make a good component library from scratch, picking a framework based on the available gui libraries is important. I would say you should pick the gui-library first and then the framework.
> Isn’t this backend-related? Generally framework agnostic?
Depends, sentry.io for example has a pretty good NPM package that integrates well with react giving more detailed errors. Some deployment/hosting solutions integrate better with some frameworks (although it is mostly a concern for SSR or static site generators projects).
I was down on the ergonomics of Web Components for a few years, but recent work has me actually excited for them as the present now. You can get some nice "Progressive Enhancement" experiences with them now.
If you are starting fresh, I'd consider taking a look at one of the lightweight options like lit [0] or FAST [1] for building your own. (Later this week or this weekend, I'm going to try to document building Web Components with my Butterfloat [2] because so far it is turning out great in my current hobby project and about to the point where I'm going to recommend it to production projects.)
[0] https://lit.dev/
[1] https://fast.design/
[2] https://worldmaker.net/butterfloat/
(ETA: Also advice I wish was more common in Web Components documentation: You don't have to use the Shadow DOM at all. Much of the complexity and confusion in Web Components is interacting with the Shadow DOM. There's a lot of great advice on why you might want to use the Shadow DOM. There's less great advice that it can be YAGNI and it is so much easier to style Web Components when they don't use the Shadow DOM, especially in your own Web Components for your own FE using a common style template like Bootstrap or Bulma. You can just ignore the Shadow DOM and use the "real" DOM.)
May you share some example UI and code of how HTMX cannot work well?
Why can't you have multi-page, but with each page being a small SPA?
For me that's the best of both world, and this architecture has served me well.
In one of the projects I worked on years before, the pages are served by Django 2, and all the fancy interactivity is handled by AngularJS (v1) (think datepickers, galleries, multi form, etc).
We would use the same controller name, and just load different JS for different pages.
It was an odd stack, but it served us pretty well.
In addition, I read stuff like "it's important to validate your data on the frontend AND server.
It's like we are learning all of this again now.
name checks out
get the mug: https://swag.htmx.org/products/htmx-sucks-mug
EDIT: lmao, the article doesn't even mention htmx and you registered the username htmxsucks just to leave a negative comment about it?
What kind of stuff have you been building?
[flagged]
Would you please stop breaking the site guidelines? You've been doing it repeatedly and we've asked you to stop many times. Here are another couple of recent cases:
https://news.ycombinator.com/item?id=42753571
https://news.ycombinator.com/item?id=42589242
I really don't want to ban an account that's been around so long and has contributed many good things in the past, but it's also not ok to degenerate to this level. Also, it sets a terrible example for other users.
If you wouldn't mind reviewing https://news.ycombinator.com/newsguidelines.html and remembering the intended spirit of the site and sticking to it, we'd be grateful.
p.s. I have no idea whether the GP was right or wrong, but it doesn't matter. We need you (i.e. any commenter here) to follow the guidelines regardless of how wrong someone is or you feel they are.
Server rendered HTML is all well and good until you want to add native apps or a first class API layer. At that point, it makes more sense to have the web be just another client and move as much business logic into the API layer as possible.
There's absolutely nothing preventing you from emitting JSON (or whatever) API responses from the same controller logic that renders HTML.
Rails makes it easy.
A native app is more than just translating each html page into a screen. You’ll likely want to build a data model that you use throughout the app, instantly load as much of the next screen from data already fetched as you can, etc.
Having a flexible API tier makes that more ergonomic.
Nobody said anything about translating pages into screens.
The point is that the data model (and hence, the API design) applies equally to a web UI or a native application. The issues you're raising also matter for making webpages fast. When you think about the data model design before you make the presentation layer, in almost all cases, the choice of what you render is basically a straightforward transformation.
> Nobody said anything about translating pages into screens.
Well, someone did. The person above them said you can just map your Rails html routes into JSON returning routes (translating pages into API endpoints).
Which obviously gives you a suboptimal API since data access is tied to Rails pages instead of having a flexible, deliberate API.
And once you build and have to maintain the latter along with the former, you are now duplicating work. It's a familiar issue for people who have built SSR apps.
> The person above them said you can just map your Rails html routes into JSON returning routes (translating pages into API endpoints).
That was me. And no, you misunderstood. I said "controller logic" -- Rails (and any other decent web framework) allows you to map routes to endpoints in the code. In the simplest case, that endpoint could be used for an API response or a webpage, and just render different things. Alternatively, you can even have API routes mapped to a slightly different top-level endpoint, which does the vast majority of its work by calling the same set of downstream methods as the webpage version. Or a thousand other variations on the theme.
In short, assuming that you don't just structure your code as one gigantic function for each route, it's not hard to do, or hard to maintain. You do have to think a little bit about how the controller logic fits in with the API and the webpage structure, and I contend that this is the actual, practical reason that we've seen so much burdensome (over)use of React, GraphQL and the like -- those things are separate teams at many companies, and the "decoupling" theoretically unblocks the teams.
Even with react, we have found that having a separate API layer was more ergonomic.
Maybe with graphql it is different
First class API layers and native apps require such a massive amount of work (and money) that your app emitting HTML is the least of your problems.
This is not 2011 when every website was building an "app" for native experience. If you are not building an Uber or an AirBB, you will probably manage.
Those that want to make it right deliver JSON as well.
Those that want it easy, use Electron.
People in the comments talk all about their favorite pet tech stacks with only a single purpose: how long it takes them to write code. In front end logic that typically means putting text on screen or interactions.
Years ago I decided to not worry about those concerns and it turns out those concerns are irrelevant. Writing content, really all front end logic, is as fast as you can type on a keyboard irrespective of your tech stack. Just about everything else is over engineered insanity. That was even true back in the IE7/8 days.
It became apparent to me the only thing that mattered is time to refactor. The larger the application is the more true that becomes. The things that help with that the most are type annotations on everything, high execution performance, and fast test automation. Everything else became a distraction or noise that got in the way. The application does what it promises or its defective. It can be modified quickly or good ideas are abandoned for risks or costs.
So I don’t worry about tech stacks and spend too much energy on execution speed.
A friend mentioned this made the front page. I'll try to answer any questions on our approach at Scholarly. Thanks for reading!
> Let’s assume that making a JS change costs twice as much time a Ruby change, which I think is being generous to JS
I don’t grok this part. Based on my experience with RoR and JS/TS, making changes in TS-land is much easier and quicker than dealing with Ruby.
Is this just a preference/experience thing in the end? For you and your team RoR is faster/easier, so that makes it the better choice. For a different team JS/TS may be faster/easier, so that makes it the better choice?
Haven't written much TS, so can't speak to that.
I should have made the distinction between client-side and server-side JS/TS. Familiarity and expertise will be a main driver of productivity for a team, regardless of language/framework. For us, that's RoR.
Client-side JS however has a multiplying property, where we often need to write more server-side code to accommodate the growth in client-side code. If the client-side code is providing undifferentiated value (e.g. authoring HTML), we now have more pieces in our system to accomplish our goal (author HTML). What's been surprising to me is that you don't need to author HTML client-side to have a reactive experience. With Turbo, Stimulus, and server-rendered HTML, a great experience is possible with fewer layers.
Great answer. Thanks!
I think the power of fat clients comes when you have different consumers of the same APIs/logic. Like a browser app or two, maybe backend services, a few task queues, etc. Then having a clean separation between client code and business logic becomes super valuable.
In my experience with SPA we got to a point where my team could go weeks, even months, without having to make changes in server code. Whole new features that were fully supported by our existing APIs because they were written as reusable APIs. If you’re having to write a bunch of Rails to support the growing client code, you probably didn’t need a separate client yet.
But when your codebase gets to that point even Rails is just a frontend really. So it’s mostly about which tradeoffs you prefer. Unfortunately I left Rails right around the time Turbo was becoming a proper thing you could use so I don’t have the best feel for what it’s like.
Thank you for writing this all up. Just curious if you ever considered switching away from Ruby? I think many people are living in parallel stacks (TS, Go, Python, Rust) and it would be interesting to hear how it’s been going more recently in that ecosystem from your perspective.
As to rendering, I’ll be honest and say that my code has moved more towards client-side (using ConnectRPC and my framework ojjs.org—-shameless plug :), but I love that you have had success with a different path. Super interesting, and thanks again!
I don't have a reason for switching away from Ruby at this point in my career. Things can always change down the line. Maintaining multiple languages at the same layer sounds like a personal nightmare to me. I'd rather learn to write PHP and have that be the only language, than to write Ruby+another language on the server-side.
We're building our company on Rails because we think it's the best choice for a young company, since it allows us to respond to customer feedback more quickly. That's what we're optimizing for right now!
Did you give inertia a try?
I think the idea of "sprinkling" JavaScript into your server-rendered HTML is a good one. However, I think that Stimulus is terrible.
1. There isn't a good way to test it. There is nothing in the docs about how to test it.
2. Keeping state in the DOM is dangerous
3. Messaging between Stimulus controllers is painful
4. They disconnect parameters from functions. The functions have to scan through the DOM to find what they need which I think is fundamentally weird
5. Reusability is rare
6. It doesn't try to play nice with the larger JavaScript ecosystem.
I personally prefer Vue.
Reg. #2 - I returned to frontend dev. after years for a hobby project (and even earlier, my frontends weren't very complex, I could get by with jQuery in the pre-React days), and I am surprised to see this is popular (or at least a supported feature everywhere). I would also think #2 is dangerous, but I am wondering if its just me being simplistic. Aside from a thin layer of reactive controls, when do people need #2?
Care to elaborate on #2?
In the "old days" I'd colocate data as HTML attributes:
We'd use this data for any number of purposes to build out other little features that'd rely on the attributes.I think the key takeaway of the article is:
> Code is not an asset, it’s a liability.
> What is the least amount of code we can write and maintain to deliver value to customers?
regardless of HTMX/Bootstrap/react, the simpler the better.
Watching Meta rewrite Messenger twice without success was enough for me to never touch React for any large project, especially after that botched e2ee chat rollout.
You think the major complicating factor of rolling out e2ee was that they used react?
Given I was able to see the errors directly in the js console, yes. You used to be able to break everyone's state by putting an emoji in a URL.
I was hoping for stronger rationale than this. This is not a React-specific problem.
Of course it's not a "react problem". It's a skill issue created by the reality that React is incredibly difficult to scale in large projects.
If Meta cannot even handle React, what hope is there for the rest of us?
You really think Messenger isn't successful? You think any issues Messenger had was because of react?
Do you have sources on this?
I didn't say Messenger wasn't successful. I said that Meta rewrote Messenger twice and did not meet their internal goals both times.
Even today you can see Messenger completely break down if you have to sync for more than ~30 seconds. JS console fills up with errors about your broken state as you start to lose messages. Local storage is out of sync, session state breaks, and it's all right there in the console. It's been like this for years on WebKit. React just has too many bugs for a complex behemoth like Messenger.
React Native is just as bad and basically everyone I know in real life can corroborate lost messages, broken group chats, horrible photo experiences, and memory leaks!
You can just look at Messenger vs WhatsApp and the difference is just night and day in the user experience. The e2ee backends are the same (according to my pcaps, I could be lying), it's purely the front end that changes - and you won't find anyone that says Messenger is better than WhatsApp.
The only UI framework I’ve ever used that I didn’t absolute hate is DearImGui. I realize it doesn’t produce polished, professional looking UIs. But my god is it the only thing that doesn’t suck.
JavaScript and ReactJS are at least 10 times less efficient to write than C++ Dear ImGui. That’s so crazy.
I feel the same about DearImGui. Want a list of sliders, bam, it’s done.
So I started working to create my own UI framework with some of the DearImGui feel but being a bit more scalable.
Recently I just added basic CSS [1]. Super fun to get it working but it’s been a lot of work combining UI styles. But it’s cool getting 60fps live animations in a 4mb binary. Hopefully CSS can help get it looking good.
1: https://blog.elcritch.net/why-i-settled-on-css-for-theming-i...
Dear ImGui isn't for end-user facing UI.
Did you read my whole comment? It feels like you didn’t read my whole comment. Because I said “I realize it doesn’t produce polished, professional looking UIs”.
I don’t think that’s an intrinsic quality of a DearImGui type API design. I’m reasonably confident it could produce a professional end-user facing UI. And that it would be perfectly performant and battery efficient.
Yeah, drawing everything to the screen every frame makes a lot of things easy. You can just update state and it will get drawn on the next frame.
DOM UI libraries like React have the harder problem of surgical tree updates since they can't just redraw from scratch.
It's where all of their complexity comes from. Not even React's basic primitives like useState would be necessary if you were just going to redraw the whole UI on the next frame.
Good luck making that immediate UI accessible.
Why is immediate-mode fundamentally incompatible with accessibility?
React is "immediate" so it probably could work. However the accessibility tools in that case operate on the rendered DOM layer. Without such a "retained" structure it would be very hard. You can imagine web accessibility tools wouldn't like it either if you rebuilt the whole DOM on every change instead of only updating the changed parts.
> but I think the “fat client” era JS-heavy frontends is on its way out
Look, you might be right! I still think it’s not the right tool for all situations. But this has been said over and over for at least ~7 maybe 8 years for what I can remember and it’s yet to be true, for better or worse. We’ll see though!
The older I get, the more I find myself gravitating toward building with Express.js, using front-end HTML with a touch of Alpine.js—and that covers 99% of my use cases. React is mostly an overkill.
> p75 at 350ms
Is this really that impressive if you're prefetching? Surely a cached response is <50ms always. What's the prefetch cache hit rate?
If it's anything like remix/react router prefetch caching, it's also useless on mobile. Depending on your target market, that's a huge difference
On the contrary, I would say the end user's device has never been more powerful and it will continue to get better.
In real world we are supposed to use that resource(client side compute/storage) to balance the server side and client side processing, not just for performance but for optimal user experience.
This is not exactly true, or at least it's misleading. I recommend reading some Stuart Russel's articles on this or watching some of his talks.
In summary, performance is getting better on the high end, but at the same time, large parts of the world are coming online with terrible devices, so median device is not very good. P75 device is totally removed from what web developers use to develop on.
On top of that, there's still a big concern with battery life, spotty connection and apps competing over phone's resources. E.g. on Android, if your website is too heavy, the system will kill stuff running in the background. If your users watch youtube or listen to a podcast and your website make the audio glitch or kill running spotify, that's not a great experience.
Last point is that react-like sites use the phone's resources in a really bad way - phones get more cores (especially e-cores) and special processing units (ai, video, graphics) but JS runs single threaded on the UI thread, competing with everything else, together with expensive JS engine machinery. If you ever profile some SPA on some representative android device, it's just all yellow, bottlenecked on JS.
Went all in on the BALL stack (bootstrap, alpine.js, laravel livewire) and couldn't be happier
> BALL Stack
Remove the T, it's cleaner.
> One of the arguments for a SPA is that it provides a more reactive customer experience. I think that’s mostly debunked at this point
That's not true. You absolutely can make edge applications faster than anything running server-side. A great example is Linear, it can switch between issues within 100ms (it even supports hjkl keys for navigation!).
But this requires you to be EXTREMELY careful. In case of Linear, they're using a sync engine to replicate the data onto the client side, rather than doing the request/response model.
A few more examples of good SPAs are SoundCloud, Twitch, and YouTube. They all have the players move between interactions, which (generally) is better UX. Soundcloud in particular, if they didn't have the persistent player while browsing the site would be nearly unusable.
> A great example is Linear, it can switch between issues within 100ms (it even supports hjkl keys for navigation!).
That's nothing special and definitely easy to achieve with a server-side backed MPA.
A triple handshake to a datacenter across the US is already ~80ms. It can be mitigated with HTTP2/3 but that still leaves you with not that much time to serve the request.
It's certainly doable, but not at all straightforward to make it reliable. A local app, on the other hand, does not depend on the network latency and the server load.
But then... if no network latency I would expect much better than 100ms.
It often is. I'm just saying that even for pretty complicated cases it's still within 100ms.
I'm just hoping 2025 will be the year of Vue or Svelte. Maddening that people are still picking React over much superior frameworks like those two
What makes Vue or Svelte different?
Is it more abstract? Is the state model simpler?
I have my issues with react but I don't think a different framework necessarily solves those issues since those issues are explicitly with how you need to handle state changes in JS and how "components" tie into that.
I haven't used it but something like Elixer Pheonix liveview[1] / .NET blazor[2] or skiplabs skip[3] or a well setup apollo client[4].
Nothing prevents you from building that abstraction on react, I don't know about Vue/Svelte.
The idea is though that there are models which should come from your backend, viewmodels which should be in your frontend code. And there should be no other state.
Whether a button is clicked or not has nothing to do with the backend. What the button does when it is clicked also has nothing to do with the backend. All that should theoretically happen when the button is clicked is you should decide what needs to happen. If a thingabob needs to be deleted from the viewmodel, no calls to.the backend. If that thingamabob is linked to the actual model then no frontend should change, the backend should change and a message that it has successded / failed should go to the frontend.
It's when you bring optimistic updates and eventual consistency etc in, then your frontend code becomes absolutely chaotic. You make it a distributed computing problem but then instead of message passing and actors which is a known good way to handle distributed computing you try to synchronise state.
1. https://hexdocs.pm/phoenix/Mix.Tasks.Phx.Gen.Auth.html#modul...
2. https://dotnet.microsoft.com/en-us/apps/aspnet/web-apps/blaz...
3. https://skiplabs.io/
4. https://www.apollographql.com/docs/react
Never thought about SSR making your code more testable. That sounds pretty appealing.
Also, does p50 mean median?
It's much simpler to not write an entire second application in the fucking browser, which is what React et al frequently entail.
by fucking browser you mean the client? That's actually the most important place you want to have an application, unless you are developing a blog.
Depends on your perspective. Everything I write is in the browser, there's very rarely much server side bit.
Yes
Its somewhat amusing to me that in 2025, you can still find comments equating React to hype. I've been using React professionally for 10 years. Can we at least agree its not a new, hyped technology?
IMHO there's exactly two factors when it comes to having success and efficiency with established tech like React or Rails. One is familiarity, the more experience you have, the more you know it, the more you like it, the better you are going to be with it. The other is restraint. The less custom EVERYTHING you make, the easier it will be to maintain and change. If you lack one or god forbid both, you are going to have a bad time. If you have both, probably anything that's not actually bleeding edge will work out well for you.
If you don't over complicate it, React apps are very simple. Emphasis on the very. The opposite is also correct. If you DO over complicate it, React apps are extremely complicated.
Also, the SPA model works great for some apps and badly for others. This blanket ruling of "do x and not y because x worked for us and y didn't" is just bad advice.
Simplicity is relative. I wouldn't call having to reimplement basic browser features like forms simple compared to slapping Turbo on server-rendered HTML (which took me ~50 LOC last I did so on Pocket SQL).
It is. And it's very much domain dependant. One of my projects is a CRM application, which is a SPA. Years ago, I had a similar incarnation of that projects as a "traditional" html+js model. It works much much better as an SPA on many levels. It's a complex app with a lot of UI elements. A simpler application might not benefit from being an SPA. So it all depends. I'm just allergic to that style of "X is dead to me so X must be dead to you".
That's interesting because a CRM sounds like a strong use case for server-rendered HTML: Relatively low interactivity outside of form handling, which is consistently a weak point for SPAs. I wonder how different your experience would have been back then if you had modern browser APIs and something like Turbo, because the manner in which you go about the JS makes a huge difference. I would not advocate that people use HTMX for example, which strikes me as just being inline JS.
An SPA is actually very suitable for this type of app. It was simple forms in the 00s, but it's not that anymore. First, in my case, the back end is an API (python). It is also serving mobile apps, and 3rd party integrations. Turbo is more suitable, if I'm not mistaken, for Javascript based applications. Second, my CRM is fast. The UI is snappy and there is little lag, which is something people comment on a lot. And third, there are many components there where a page reload will break things - for example, when you perform a telephone call from the browser. You can still navigate the data, without reloading the page and cutting the call.
It's never simple, and NEVER EVER one size fits all. I'm saying this after about 30 years of doing this job commercially.
Turbo is just a front-end library it doesn't matter what your backend stack is. You can do all of that with a MPA approach, including partial DOM updates, with just the JSON API for your mobile apps being the missing part simply due to not needing it for the browser implementation. Serializing JSON on the backend and transforming it into HTML via React should always be slower than just sending the same HTML over the wire. I'll have to benchmark Pocket SQL to get frontend numbers, but it is perceptibly instant with requests taking single-digit ms, so it's not like the server-rendering part of it is slow. I'm glad the SPA approach worked out back then! The point I'm making is that MPAs are worth another try with modern tooling.
It's interesting to hear varying takes on this.
But my personal belief is that web apps are moving towards static sites that are cache-friendly and offline-ready. This for couple of reasons, first is easy integration with CDN. Second is easy integration with webviews for mobile apps.
And easiest way to implement offlineness so far has been through a state management library. Doesn't mean that doing what the article suggests, moving logic to server, is impossible but it's quite a pain. Much easier is to move logic to client and handling it there.
Moreover, the fact there's so many UI components and libraries available for React and so forth, makes developing much faster. Depends on the developer, of course (and I personally prefer Svelte), but is a rather big advantage if you are doing anything complex in UI.
I think this varies wildly on the type of app you're building. If you are building something like CRUD interfaces obviously a server side focus is very viable and useful since you don't have to have double state management. I am thinking apps like ecommerce, banking or management software.
But if you're building a very client heavy application that does something like Photo editing, CAD, video editing etc I have a hard time seeing a server side generated content to be successful because you need a lot of client side state no matter what.
For example, I have done a lot with maps and it's not possible AFAIK to render the canvas on the server since it's a browser only api. Also I don't really see the benefit since it takes too much computational power to generate graphical things on the server.
I agree with this, it was always the case with everything in the real world as well. People use tools that can best handle the problem they have. However, I think most today's websites/apps do not require to be SPA oriented. If only the one page requires heavy client-side interaction, there's always possibility to use SPA library only on that one particular page
I agree, most websites would benefit greatly from using something like Phoenix Liveview, Hotwire, Livewire etc. That way you get all the benefits of a SPA without having to deal with the extra complexity of double state management.
I wish I was doing those kinds of apps because that tech seems wonderfully nice to work with. Unfortunately I do client heavy apps mostly so I don't have the benefit from using one. Offline support is... impossible to do good with those kinds of tools.
Im using RTK Query with React with apps where i dont control the API and just consume the JSON.
The problem with RTK Query is the strong reliance on the internal cache, which is often in the way, since i need the updated data from the server most of the time, but otherwise it works quite well.
For apps where i control the backend (mostly PHP with Laravel or Symfony), im using Inertia now, which enables me to directly access the entity/model data in the React code, without any API necessary.
This works really well and reduces the React code to the minumim, UI based stuff, where it shines.
There is a Stimulus/Turbo plugin for Symfony as well, but Im not sure if this technology isnt too niche and unproven yet, in contrast with React, which has been around a long time, has tons of docs, and also loads of devs with experience on the market.
I removed all of our React and replaced it with Web Components, and I'm not missing anything.
I'm sticking to cached static resources, and just sending data over. Not rendering from the server, but not writing single-page apps, either. The more you render from the server, the larger your caches end up. Not doing that for HTML.
Just HTML, CSS, and JavaScript. No tooling. No building. Web Components and fetch(). No frameworks on the client-side. Express still on the server.
I'm trying to optimize for not swapping out dependencies on a several year scale, and it's working out pretty well so far. I removed React because they're not interested in UMD builds anymore, and I'm not going to jump through hoops to make it work on my end, either.
Same, and I've found this works quite well with a C++ backend. Just send over binary data as struct-of-arrays, load it into typed arrays, render components. Your app will be bottlenecked only on bandwidth, as it should be, even for heavy 3d applications.
There's nothing fundamentally stopping react apps from being fast like this, but the dependency snowball has a way of hiding accumulated dynamic memory allocations and event listeners. Instead, we should be intentionally grouping allocations and events, keeping them contained to a few well understood pieces of code. Without this, these apps could be ported to native C++ or rust and they would still be nearly as slow because there is no magic language that can make a slop of millions of tiny dynamic allocations fast and low overhead.
C++ backend? Could you elaborate please?!
If most data between the backend/frontend is raw numeric array binary blobs, and you target array types that can be loaded directly into JS TypedArrays (int32_t* -> Int32Array, float* -> Float32Array, etc.), you have a more or less optimal data transfer mechanism with zero dependencies. The JS parsing is faster than the fetching, even with 10s of millions of items, provided you keep the number of arrays fixed and reasonably small.
This is a natural fit for data-oriented programming in most systems languages, including C++. It's also compatible with numpy and any other dynamic language backends that have a performance-oriented array primitive or lib. The data can be served dynamically from memory, or written to files on a static server like nginx.
I find this no-nonsense approach very appealing.
> The more you render from the server, the larger your caches end up. Not doing that for HTML.
Is HTML really that much larger or complex than JSON? Based on the following it seems to be only +10-15% larger (n = 1 dataset obviously).
https://github.com/1cg/html-json-size-comparison
Is the amount of data transfer the main reason to use JSON or do you find Web Components play better with JSON payloads? I could imagine the template string being rendered on the server, fetch()-ed by the client and swapped with this.innerHTML.
Do you manage any amount of cross-component state? It's one use case where JSON would win over "HTML over the wire".
What kind of project did you "remove all React"? Also, curious whether you ended up with vanilla Web Components, or fast-element/LitElement/others?
Completely vanilla, just using the web standards themselves.
this.innerHTML with a string template prefixed with /* html */ so syntax highlighting is applied.
Interesting- how to you handle templating?
I was apprehensive at first, but it seems like it works for them and they make some interesting points.
I got so sick of having to deal with thousands of dependencies with a React project, I manually implemented JSX to string components (e.g. building with ESBuild then writing the createElement and fragment functions as my own package, which would return a string to render server side), added Alpine.js, and it's just as, if not more productive than standard React.
So many fewer packages to deal with (especially if you want to SSR your app), and my site is way faster. And I get to use JSX which is my favorite templating engine and requires little porting from my React app.
I suggest people really take a look at Alpine.js, you can do everything in it as you can with React and it's a significantly smaller, simpler package that runs right in your browser.
Recent react versions have almost no dependencies, everything you add on top of that is on you.
https://www.npmjs.com/package/react?activeTab=dependencies
https://www.npmjs.com/package/react-dom?activeTab=dependenci...
If that's too heavy by itself, preact might be easier/simpler than reinventing the wheel.
It's more not wanting to use virtual DOM and only wanting to render to strings for SSR. For example if I use useState or onClick handlers inside the JSX template, now I'll have to handle both client and server side code at the same time, which I want to avoid. If I only render a string from my JSX templates, I can separate all client side logic to Alpine. Easier to test and less overhead.
Can you provide more details about the project you are talking about? I somehow doubt that a website like facebook would be easier to write and manage in a minimalist framework. I'm not sure the only project I have written React for would compare to something like facebook but it was a pretty complex SPA that I seriously doubt would've been better written in something like alpine.
Sure React may be overkill for a personal blog and no one is saying it isn't but I wish people that have ported from React also assess honestly the complexity of the app we're talking about
I have a website I use to host all my personal software. This includes a front end portfolio with various somewhat complicated data applications, I have a personal notes app, RSS reader, content feed algorithm, games, e-book reader, and S3 file manager. You are definitely right that complexity isn't as big in terms of number of users (for me, it's one), though I'm still making functionally complex applications.
Facebook is obviously going to have a ton of shit going on all at once, though for the vast majority of sites it's mostly just some form or another of CRUD with perhaps some somewhat complex front end UX.
You can build many web apps without React. To me the secret is with JSX, which makes everything way easier to manage.
Realistically the only issues with using a more minimalist framework instead of React is global state management and persistent components on page navigation. Global state management in Alpine can be done with Alpine.store and persistent components can be implemented with either Hotwired Turbo, Alpine AJAX, or HTMX. Are these things better than React Context/Redux and React Router/Next Router/Some other router? Probably not. But it does work.
I wouldn't recommend this approach for actual businesses, mostly because devs will already know React and thus be more productive. But I think it's genuinely a viable approach for building web apps.
> I wouldn't recommend this approach for actual businesses, mostly because devs will already know React and thus be more productive. But I think it's genuinely a viable approach for building web apps.
That's just the thing. Businesses chose a specific stack because the campaigning for that stack won out amongst any competing stack, not because that stack most closely aligned with their requirements and needs.
Boring Anecdote Time:
I do contract work. All current frameworks have a velocity for new API/endpoint creation (with DB schema modification) of between 4hrs - 8hrs (spread out over 3 - 4 PRs)[1], assuming all the PRs come back with LGTM.
My home-grown b/end framework cuts this down to between 5min - 20min (one PR only) for the same API/endpoint addition.
However, I only use my home-grown b/end stack for full webapp development, when a client wants a new system, and only when that client is not a technology company, or doesn't have an in-house development team.
That's because most businesses are using what their tech teams mandate, which IME is either Java, C# or (not as common around here) a Python or Node b/end.
Once(!) I had a dev manager agree that velocity for MVP and velocity for maintenance is a higher priority than conforming to any of the current b/end languages, which included but was not limited to C++, Java, Kotlin, Python, Node, React, Ruby, MSSQL, MySQL ... etc.
A few months later, on a call with him he expressed how fast his dev team was iterating on my stack when extending the system. Currently they are stuck on a lot of legacy that has to be extended, but they are definitely thinking about b/end in a new way now.
[1] Assuming the usual workflow of PR for ORM changes, then PR for data object layer + unit tests, then PR for domain object layer + unit tests, then PR for business logic + unit tests.
Very few websites are like Facebook.
Facebook is in many ways terrible. it can be hard to work out what to do, it can be glitchy (for example updates can be slow - stuff is presumably cached and takes time to update) and its VERY hard to manage reasonably active FB groups.
Yeah sure the facebook frontend has a lot of issues and is frustrating at times but I'm not sure the random slow updates or even failures to load the page / partial info is React's fault
> Many interactions are not possible without JavaScript, but that doesn’t mean we should look to write more than we have to.
PREACH. And many site actions can be handle server-side without degrading the user experience.
I have a 6k monitor. why are you embedding a 1400 px image I can view fine into a little 640px column which makes it hard to read?
Sorry. Will try to fix
I don't know React very well but I used Angular in a large project and it was completely baffling to me how overly complex it was. In certain areas of the application it felt like it was completely unpredictable what value the state was going to be.
I sometimes long for the simplicity of something like Windows Forms.
I've spent my teenage years making Windows Forms applications, and the complete lack of state management isn't something I'd like to go back to.
Sure, with the knowledge I have now I could set up a whole MVC model with event based updates to form state, but at some point you're just rewriting the complex libraries that you're trying to avoid.
Good interactive state management, especially when you're tying to combine it with a stateless protocol like HTTP, is very difficult. Every complex library that's out there started off as a "simple way" of doing things.
There's nothing stopping you from doing Windows Forms applications of course, and the modern evolution of ASP.NET does look pretty inviting if you're over all that frontend crap, but don't underestimate the problem libraries like Angular solve. Microsoft tried it with Blazor, and that'll quickly get you a website that's a hundred megabytes in size because it downloads all of .NET into your browser.
By that chart, it looks like you moved that code to the server. Which is fine - I prefer the back end these days too - much easier to monitor and reason about. Especially for a cloudy app. Not so great if you are going for the offline-available featureset though.
Where did we go wrong? May be we need something different from HTML. A new spec to render user experience. Possibly same spec for Browser & Native apps across all devices.
I’m building an application with much the same stack and it’s refreshingly easier for a one man shop to use the tools he describes.
I used React at my previous job and it feels like a nightmare thinking about it again. Hotwire is a simpler approach that pays off.
Full page navigation is the web's super power and what makes it scale.
In my view one of the first things you should be doing when working on a web-app is to work out where you can place them, rather than trying to avoid.
Really hope there are more in Rails 8.1 and 9.0. More extracted tools, more defaults, higher performance. I mean we really should be aiming at p99 350ms.
But, was it JS alone or the rendering of JS and CSS in the browser container???
For context, the Dart Flutter stack started out with the concept to make web apps faster....
Do you also have a native app? How do you plan on using your current setup with Swift?
How about Hotwire Native?
https://native.hotwired.dev
https://pragprog.com/titles/jmnative/hotwire-native-for-rail...
From slop to even bigger slop, congrats!
We're four years into a journey that shouldn't have worked but did. I have a lot of experience with mostly server side JVM stuff and a little bit of frontend. Before 2020 that was mostly standard stuff including a largish javascript /typescript project and a bit of react.
In 2020 I took over the skeleton team of a startup. My main (junior) developer had a bit of Android and Kotlin experience; not a lot. We had no resources to get more developers. I was focusing on building the backend, which barely existed at that time so it was all new code. I picked spring boot and Kotlin for that.
We needed web and IOS apps in addition to Android and the Android app (the only thing that had been built) was a bit of a mess and honestly there wasn't much worth keeping. And with just one developer it was clear the replacement was going to be a web app. The obvious thing would have been to potty train my junior developer on react/typescript and hope that after a few months he would become a bit productive.
Instead I took a wild bet on kotlin-js. I honestly did not expect that would work. But it did. We did a brief research spike. Very successful. My junior developer did all the work. And we continued from there. I always had the plan to at some point just parachute in more developers and re-do it properly. But that never happened and nor is it needed.
Fast forward a few years, we still work with kotlin-js. Over the last four years that became more stable and better supported. It's great. It's a four year old UI code base and we're making lots of changes with confidence all the time. Kind of the gold standard for a good code base. It sure has its issues but it's under control.
Mostly I can't tell the difference whether I'm working on server or frontend code. It's all Kotlin. Kotlin multiplatform ensures we can reuse a lot of code on both. So the default place for code to go is in some multiplatform library. Which then ends up being used on both server and client.
We use a small, obscure UI framework for kotlin-js called fritz2. It emulates a lot of what react does but in a Kotlin friendly way (strongly typed, co-routines). We use tailwind for styling (after some adventures with other stuff) and are slowly converging on maybe adding daisyui to that mix (which is nice).
A lot of stuff in browsers is of course asynchronous and as it turns out, Kotlin's co-routines are awesome for that stuff. We have a lot of long running or recurring stuff happening in background co-routines. Handlers are suspend functions, etc. Integrating existing javascript frameworks is fairly straightforward. We have a few of those. Things like maplibre and a few other things.
The point here is that frontend code doesn't have to be Javascript and it doesn't have to be miserable like many Javascript projects become. Where you run your code and what language you pick for that are two independent choices. And if you have proper well designed code, it should be testable. Just because it runs in a browser is no good reason for that to stop being true.
I wouldn't recommend my choices four years ago. But at this point browsers run a lot more than just Javascript. Getting stuck with that stuff is a choice, not a necessity.
Angular apologist here. Learning curve is somewhat steep but I can be immediately productive in it and testing is built into the framework as a first-class citizen. Routing, debugging, state management, SSR, it’s all there. I like the separation of controllers, HTML, spec tests, and CSS because it allows the developer to reason about these separately. DX is damn good.
In fact I recently whipped up a front-end UI in a few days using the BAEL stack (Bootstrap Angular Electron). You still need the data layer of course, but this would be true of any UI framework unless you want to go full monolith like Rails (which I still fully believe is a superb solution).
And having done Rails, React, Angular, and a mishmash of other frameworks, libraries, and architectures, I can say that a “pure” Rails app out of the box is impressively good for most use cases, especially now with Turbo.
Unfortunately for many of the HTMX/Turbo people, they did right to identify the problem but they have the wrong solution.
The way to alleviate those issues is not to bloat the frontend with things that shouldn't be in it nor is it to fragment the code base with never ending "sprinkle" of JS.
The best solution is something like Gleam's Lustre, where you use the right tool for the job, while keeping a coherent code base:
https://blog.nestful.app/p/gleams-lustre-is-frontend-develop...
Maybe it’s the changing interest rates or political winds, but I think the “fat client” era JS-heavy frontends is on its way out.
This is just not going to be true. It’s an AI world and we need to funnel so much high velocity text and dynamic UIs to provide a high fidelity experience.
Investing in static server rendered pages is just a surrender, the long surrender that people desperately seek from the onslaught of JavaScript.
But it won’t happen, it will either be JS or another language, but server side pages is the wrong bet.
I'd encourage you to spend an afternoon kicking the tires on Turbo/StimulusJS, HTMX, Laravel Livewire, or Phoenix LiveView!
I can't agree with the quoted sentiment either. Even I attempt to remove all my bias, most of the tools I use to work (app developer) are fat javascript clients.
Yeah. There’s been a little bit of a puritanical pursuit back out of SPA on HN (it might actually be isolated to here honestly, almost like a local band that plays in the neighborhood), but it’s an emotional over correction (imho) to the exhausting JS climate.
Nevertheless, the facts on the ground are the facts on the ground.
> It’s an AI world and we need to funnel so much high velocity text and dynamic UIs to provide a high fidelity experience
Are you on drugs?
[flagged]