Things I wish I knew before moving 50K lines of code to React Server Components
mux.com
mux.com
I noticed this too. You can put a plaintext file on the server and it gets transferred to the browser pretty fast. You can also put another plaintext file ending with .css on the server and it can make things on the first page move and look really nice just because the browser knows what to do with it.
It’s a neat trick but still second to useful content on the first page (that is the page you get to read, if it lets you).
Simpler times.
Quoting[0]:
"The entropy of a system can in fact be shown to be a measure of its disorder and of the unavailability of energy to do work."
I rather like that - where "work" is the time spent solving first order business problems, and "disorder" is a measure of the energy spent not directly solving the business problem. AKA dealing with accidental complexity.
[0] https://www.coursehero.com/study-guides/physics/15-6-entropy...
(though seriously, in my dorm room in the 90s, my pentium 90 desktop at the end of my bed had a fixed IP address and was the server...)
There were some cowboy-level engineering practices for sure, to the point that I'm not sure you could call it 'software engineering', but there was definitely some beauty in the simplicity of that setup compared to what we typically have to do these days. At least after you set up the box and the access to it, anyway.
By the way, we need to add another feature to our page, would you mind looking through that file so there are no class collisions? What do you mean its too long? 50k lines? Pfft.. But at least it 'gets transferred to the browser pretty fast'
Do not awaken the Ancients for only the pure of heart will survive such an encounter.
I swear you js haters never fail to make me laugh with all the ignorant lamentations.
> When disagreeing, please reply to the argument instead of calling names. "That is idiotic; 1 + 1 is 2, not 3" can be shortened to "1 + 1 is 2, not 3."
Let us not sink into unproductive musings of the intellect, but meditate on the nature of the pendulum swing.
I would be careful assuming too much about us, who are wise in the ways of the world and, dare I say, exceedingly goodlooking.
Wouldn't the same be true of "JS era" developers who never learned the basics of a static website or a templated server-side app? If the issue is being too lazy to have more than one tool in your toolbox, then it applies to everyone.
Could they have been joking that, maybe, there’s a lot of folks who are a little too tunnel visioned on the newest most modern js metaframeworks that they have little or limited knowledge of the foundations of their ecosystem? Given that you know something about html files and basic web servers, was your position necessarily the original subject of the joke/point here? Surely it was! Gruff old school devs are so obstinate and short sighted haha.
You opened, intending to construct an argument on your genuine position, with a massive strawman, on a lighthearted commentary over a line from the article that was purposefully taken slightly out of context- not even remotely a tirade on “js hating.” You’re not having an argument in this comment thread with anyone, because no one was even discussing anything to begin with.
I think there’s things to laugh at here (like the original joke) that aren’t how genuinely stupid you think the commenter who is ironically replying to every of your comments in a vague and mystical tone.
Seriously though, I saw someone described as a 22 yr old software engineer in an article. There is a better term: "Software Engineering Apprentice"
It's not just about wage, it's about assigning appropriate work to peoples level and having them progress through the most efficient steps to mastery while also completing billable hours
that's the opposite of what a union does. A union rewards seniority and nothing else.
In particular, it's the assignment of work to the union and then the union is responsible for pairing workers with the assignments which enables the union to create a training funnel where different requirements of the same job can be split among different workers of varying seniority such that apprentices are able to work on the easier items even when there are things beyond their skill involved in the overall work assigned to the union.
Typically a union does primarily exist to create CBAs for wages but this is another function of them which I think would be very helpful for SE and future protection.
So maybe not a traditional union is necessary, but I think there are some functions more or less exclusive to unions right now that would be beneficial to apply to SE. Hopefully that makes sense
The problem is the dogmatism of it all. If you point to a simpler and a more obvious solution, your coworkers will ridicule you and turn you into an old man pariah.
He talks about using WASM for applications and HTML/CSS/JS for basic websites.
What does he suggest we do about the UI layer? Draw pixels on a canvas from WASM?
Yes he says to use a language that compiles to WASM for the UI parts to draw pixels on the screen.
It really seems like WASM will be the write once run everywhere runtime that was touted in the past. Java almost got us there but was too dependent on Java, whereas WASM is for any language. I've been using Flutter with their experimental web WASM support and it's very fast.
I hope it doesn't replace the lowest common denominator of HTML for generic apps, though, if only because it would dramatically raise the barrier to entry (not that your typical React app is particularly readable in the inspector...).
I personally use Flutter for a lot of my apps, as well as React/NextJS for SEO based apps, the combo works pretty well.
Whelps. Time to learn C++ again!
Rails/Django/Laravel/… + Turbolinks/Htmx/… or even sprinkle some light clientside JS for fancyness.
Or go best-of-all-worlds if you happen to know Elixir/Phoenix.
But don’t continue the descent into RSCs, now matter how many people tweet about it. These folks with less than 10y industry experience will run into all the basic problems we had in vanilla PHP sites years ago, I even spotted react components with inline-sql-hooks already. This time with much accidental complexity overhead!
Stay sane instead, ship actual products quickly, and earn that lambo!
So much this. It's like our industry has a rolling 10 year cycle of amnesia. We moved away from server rendered UI for very, very good reasons. Of course the SEO argument is always there, but if that's your concern just build a traditional server templated site. The vast majority of SPAs have zero need for SSR and the complexity that it introduces.
Beyond that, bundle splitting with lazy loading is very helpful, but it requires knowing that you can do it and some additional work on top of baseline bundling. Then you're nearly at parity with static sites in terms of individual page download requirements for the first view (assuming react/etc are cached CDN libs rather than bundled) but each subsequent view of that page is much smaller, faster and more responsive than static html.
In some cases, it's clear that it's a webapp and a SPA is warranted. In some cases, it should just have been a website, but yet there were organizational reasons to use react - producing technologically bad results in detriment of the users.
99% of apps are basic CRUD apps. Aside from a few interactive pages - which you could even write with React - there's zero need for this bloat.
No, your "application" is not Google Docs, Spotify, etc. It's not a SPA.
Citation needed.
You run into the edges of pure HTML forms on day 1 of the project if you have to listen to any feedback or requests from the users.
That's the crux of the issue. It's not that JS isn't needed and small pieces of interactivity aren't nice. But we chose to turn everything into JS despite only really needing it for very small pieces of the app.
Back a few years I'd have small JS bundles included in specific pages that needed interactivity. Later people frowned upon that practice because it meant a ton of requests for the client, so we bundled everything.
Now, new JS frameworks send small JS bundles as you open each page, lol.
Why not have micro React (or whatever framework makes sense) pieces in pages that need it for the interaction?
Plus, server-side form validation is extremely easy to do and also removes duplication. Its been a solved problem for over a decade. I'd even argue back-then it was harder since browsers were much worse and basic elements were lacking. Today you add a `required` attribute in an input and it simply works.
I stand by it. Aside from a few exceptions, most apps have no business being SPAs. They go on to emulate a subpar version of a MPA, and people have to resort to absurdities like these server components to achieve the same experience we've had for 20+ years with server-side rendering.
The point at which you should consider a SPA is when you are sharing data between most of the "pages" in your app, and there are multiple data sources surfaced in any given "page." In this case, you're going to have to jump through indexdb/localstorage hoops just to avoid losing that data on every page transition, dehydrating/rehydrating multiple types of records then passing them around via a context or somesuch. In that case you're on the hook for complexity either way, but the SPA version performs better at the cost of some SEO.
Can you please list your reasons?
THIS... unless you're building something that absolutely requires a full blown progressive rich frontend app, (95% of you don't), liveview will do all the thins using serverside components with minimal jaavscript.
Not just that, you'll have a serverside thread dedicated to that user which allows you to actively push changes to the user's frontend without you having to write explicit javascript handlers.
Meanwhile, the "server-rendered HTML" and "client-rendered HTML" camps are both doing quite well. I consider myself quite lucky to have both options at my disposal for every web project. I hope the work on RSC doesn't muddy React's support for pure client-rendered apps.
1. https://en.wikipedia.org/wiki/Common_Object_Request_Broker_A...
You don't hear about it for the same reason it's impolite to talk about your top 10 favorite snuff films with customers. There is no situation where it's appropriate and anyone flirting with the notion needs to be dismissed before they doom your company.
CORBA is pure evil and you should not speak its name so lightly.
Not to detract from your point, but nobody uses it because when network administrators everywhere started closing all the ports except for 80 (for "security!"), everybody moved to SOAP, that uses the port 80. And then, since the SOAP consortium doesn't have enough competency to create a full data transfer format, starting from XML and contained in a couple thousands pages of docs, in about a decade people said "enough!" and moved into what is commonly called REST.
The problem with component boundaries is there, but it's not really what CORBA did.
It's an over engineered overly complicated design that leaves a lot of crucial stuff undefined, which made interoperability impossible. From a performance perspective it was crap. And debugging an implementation was almost impossible.
It's a great example of how architects can destroy a good idea by layering ridiculous amounts of abstraction into an incomprehensible pile of software.
And it shows that architecture without implementation experience should never happen.
Muxer here, and fun fact, Elixir is a core piece of our infrastructure and has been from the start! At the very beginning our dashboard interface was all rendered by Phoenix and occasionally a page would individually include React if it was a situation that truly needed advanced client-side interaction. Given that our first product was an analytics dashboard, that latter situation quickly became basically our entire dashboard and it simply made sense to move to a full SPA taking advantage of the API we were exposing to customers anyway. This was 2016, so LiveView didn't exist at the time, but I'm still not sure I'd make a different decision for that product today.
The blog post is talking about the application that powers our public marketing site, which has a pretty different set of needs, but figured I'd throw it out there that we use and love Elixir/Phoenix! :)
More people should do this openly I think, since it’s still vastly underrated and fellow alchemists seem to be too humble to evangelize!
These frameworks were not created to solve “Simple hello world” apps.
If your career can be significantly affected by devs fresh from bootcamp
Well, there are certainly problems if that's the case. But it's not necessarily senior ICs that are the problem.I've experienced a few companies where "boot camp yahoos" wound up essentially running the show to ruinous effect. Why? They had numbers, essentially, and management was too hands-off to prevent it.
To give a specific example: we had a product where our UX was basically: fill out this HTML form to apply for a financial product. Traditional dinosaur-style server side rendering was more than enough.
The front end boot camp yahoos somehow wound up forcibly moving us to React. They got that pushed through and approved before anybody knew about it because they gave a bunch of BS stats to management who didn't care and also didn't have the technical chops to spot the BS.
The end result was that simple changes to the UX (like adding a question to the form, or removing it) required 1,000+ lines of code across multiple repos. Hundreds of hours dealing with that mess for zero gain instead of actually doing things that made the company money or improved our process in meaningful ways.
Senior ICs had no real chance to oppose this plan, and many of them were happy simply to get "React" onto their resumes.
So yeah, problems aplenty, but it's possible to be an IC and have one's shit rocked by this kind of thing through no real fault of one's own.
(I'm not crapping on React specifically here. It is powerful and there are use cases where it excels. I am also not crapping on junior or boot camp engineers. They are doing their best. It's a management problem.)
However, that real seasoned engineer is a small
fraction of the "dev team" and gets overwhelmed
by the boot camp developer's group thinking -
their opinion is just as good as the guy with the
CS degree they figure, after all, their boot camp
crowd seems to win the debates!
Oh my god. So true. Heaven help us.This wasn't a rant against React. It was about the inmates (or junior devs) running the asylum.
Please don't do that; it's effectively turning "makes minimum wage" into an insult. There are plenty of people that earn minimum wage that are good people, doing their best, and (in many cases) doing a very good job. This is exactly the kind of wording that turned various minority terms into insults, as we shouldn't be doing it.
I have also had a couple of CSS wizards that wrote all the styles by hand - sounds great until someone has to fix it, even a senior designer. In short, a well-used framework that's understood is not necessarily easier, but it does lead to an agreed-on set of abstractions that make things easier to understand. Angular and React are very much there for a reason.
That’s insanely powerful and massively reduces complexity in highly interactive apps, because it means you no longer need to think about “user did this, update this here now, and here and here” chains, and can just do “user did this, update the state” and have that state update render potentially hundreds of changes across the app without needing to do additional implementation.
But if you aren’t disciplined with maintaining, or don’t understand the difference between pure functions and side effects, and fall back to hacks to try to “make things render” or “stop wasting render cycles” you’ll end up with even more complexity than necessary.
Using react as another version of `getElementById` leads to a horrible mess much worse than writing vanilla javascript, and most people who have that complaint are doing it to themselves by fighting react either unintentionally or on purpose to show how it can be bad when abused.
Raw HTML and CSS is much easier to understand, and mandatory to understand because at the end of the day creating HTML and CSS is the only goal, but higher level abstractions can be super useful to manage complex projects, and the mental models and abstractions are the actual benefit.
Getting me "on-board" quickly with some basic furniture is quite helpful, although it requires IKEA-level infrastructure and investment to get these things in front of the buyers which is definitely not easy. Dare I sare ridiculously complex?
I have worked on international teams where it was a running joke the individuals had ended up assembling the same Ikea furniture on three continents.
Now that I'm older, in an old space, my priority is EMPTYING IT so I can go about my life. I now appreciate how permanent your space can be if you carefully deliberate each addition.
The demands of the PM maybe, most users just want something the works and gets out of their way.
> very fast and smooth ui population
Neither of which your average JS/SPA/behemoth is actually good at.
> and pretty animations.
I’ll give you this though, JS web apps certainly do rep some pretty animations, often at the cost of thrashing my CPU and ram.
Crazy idea, but maybe, if instead of spending ages building “interactivity” we just built “applications that worked”, we might actually have less mess, and build better products.
Having seen systems be built up over time that do significant things (or run on many platforms, or have lots of abstractions) a lot of the time the tougher parts are.. well, complicated. Some of those tools are to make things better for a lot of programmers working on the same project. You have to have some amount of structure then. Sometimes it’s so business people can create content.
“Why doesn’t it work simply” is often a business decision.
One still can simply drop html file and sprinkle it with jQuery.
The real promise of these is web forms with a little interactivity. Anything more complex and you start to fight with it to drop back down to the level where it’s manageable.
It’s the fighting with it that’s the issue; my experience is that a lot of devs go in to “force this stupid framework to work” mode and blow up tasks that should be 10 lines of code with no edge cases into 50 or 100 which “mostly works, good enough.”
React is by far the most adopted framework for desktop-level or near-desktop-level web applications.
Makes you feel clever.
Idk what else to tell you.
> npx create-next-app@latest
Press Enter a few times for default settings and voila, you have a hello world app up and ready to run.
- npx: command not found
- install node / npx
- npx create-next-app@latest
- realise your node is too old
- install nvm / node
- npx create-next-app@latest
- answer a bunch of questions
- npm start
- get an error: Error: ENOENT: no such file or directory, open '/tmp/my-app/.next/BUILD_ID'
- npm run dev
- hello world in browser
It's not as simple as shipping code to the user.
npx next telemetry disable
Or set environment variable: NEXT_TELEMETRY_DISABLED=1For me it has never worked in first attempt.
On other hand Ruby on Rails bundler very rarely game me errors, and for every error provided hints what to do.
- browse to file:///tmp/index.html
browse - no browser installed
edit - no editor found
See, I can do the same thing. In any case you need a toolchain installed to actually program in the language you want to program, even if that toolchain is minimal. Complaining about a toolchain not being installed for the thing you want to do is not very useful.
Yes, as I said.
> - npx create-next-app@latest
> - realise your node is too old
Said no one ever. I can fully understand you not having Node installed (although having any kind of toolchain installed is a prerequisite for any programming so that's a weak argument against Node). But please don't tell me that somehow you will get an old version of Node after you just installed Node, because this is just reaching now.
> - npm start
> - get an error: Error: ENOENT: no such file or directory, open '/tmp/my-app/.next/BUILD_ID'
The README that gets generated with the project literally spells out the correct command you should use to run the project during development (which is not `npm start`), so this argument is also pretty weak.
And large security surface means just one compromised package is required to get on the server side. If an npm update gives you security warnings after a few weeks of a vanilla project just sitting there, something is very wrong.
Pipe dreams, my friends. Pipe dreams.
But I get what you mean; reloading a page is fine for simple pages, anything bookmarkable, but there's heavy weight pages on the one side, and state on the other. With hot reload, we're currently developing a React Native app, we can e.g. type stuff in a form field, update code, and the stuff will still be there while the behaviour around it changed. It's neat. While I miss native iOS development a bit, I don't miss the recompile/relaunch cycles.
There is overhead with working out where something, should be rendered but, in my experience, a lot of the issues are raised at compile-time and are quite transparent (the articles overstates the issues you have here, there is mental overhead but it isn't bad). The SPA period of React was awful for complexity (this was also when React had lifecycle methods, wasn't well-integrated into webpack...awful).
But seriously I have no idea of a single remotely well-known application that satisfies the above. If the modern web is so bad where are the products that prove that it can be done better more simply? There’s billions to be made if that’s true in all industries, is nobody skilled capable of capitalizing on this gold mine of opportunity wherein the entire industry is self sabotaging?
I’m left to conclude that these HN commenters with their hot takes about how the modern web sucks just generally either don’t understand what makes products successful or never have truly experienced the issues these frameworks solve for.
There are actual forums of normies and the most notorious meme factory on the internet is hardly a wonder of UX technology.
We are not on some subreddit for a reason.
This has other reasons though, like the fact that this site has better moderation and better users in general.
The simple truth is people are drawn to websites for what they get out of them.
Who knows, maybe software development is going to be fun again, even if for a few years before the new batch starts turning it into a mess.
Also, automagic, automagic everywhere. "Let me just intercept your request and send it to a HANDLER, wow." "Let me just have a magical 'getServerSideProps' function that will do magic and generate component props, but it has to live in the page, so the page gets extremely bloated, oooo."
I hate Next. And I realize "hate" is a strong word that takes some earning.
I disagree on the convenience point - it's bloat and not in the sense that people say "IDEs are bloat". It's regressive in going back to an MVC pattern in a framework that's meant to be an SPA and completely violates the "There should be one, and only one, way of doing things" principle in that it adds confusing options that people end up using in practice.
Next.js is pretty convenient, not sure why people find it so inconvenient. With the pages directory, each page is its own page, just like in the PHP days. Why do you think it's an MVC pattern? I don't use Next like that at all, it's just React.
It is jarring at first when you look at your code and say, "Wait, what else do I need to do?" And there's nothing left.
const { count, setCount } = useState(0);
becomes let count = 0;
There is no more useMemo(…) or useEffect(…). They just don't exist. There's no need for them. State management "just works" by using a store variable like $store. No more explicit subscribe and then having to remember to set up an event callback to unsubscribe and avoid a resource leak.Vanilla JS libraries typically work out if the box with it without some bespoke wrapper or adapter for your framework. ("bind:this" is really handy.)
Web development with 99% less BS. Lets you focus on your problem, not on your framework's abstraction leaks.
I myself am more of a clean, standard HTML with PicoCSS kind of dev, but that model doesn't work for everyone. Some might be surprised how much plain old HTML and the ease of development for Svelte components narrows that gap, but I'll be the first to admit the gap absolutely exists.
FWIW: Material UI for Svelte has been around for a while as well.
Just make a descriptive class name and write your CSS styles. That's it. You're done.
Okay, that's a choice.
> I wanted to move to React where I can use actual JS
You… uhh… know that JSX was literally invented as React's own HTML-like DSL, right? And that TypeScript is not "actual JS", right?
Just food for thought: HTML can exist and provide tremendous value on the frontend without JS. JS on the frontend without HTML is… not quite as useful. Be careful about which technology you want to be the central player.
Never mind that TS is a superset of "actual JS," your point doesn't even touch my argument which is that I want type safety, such as when props are missing or invalid types, and so on. Even if TS is not "actual JS," that's a semantic argument and doesn't matter as long as type safety exists. I've even written sites in Rust via Yew, works great and outputs HTML at the end of the day.
> Just food for thought: HTML can exist and provide tremendous value on the frontend without JS. JS on the frontend without HTML is… not quite as useful. Be careful about which technology you want to be the central player.
Not sure what you're talking about with this point, I never said HTML isn't useful.
But the rest of us stuck in legacy-land the toxic waste dumps of these over-engineered behemoths will be with us for years to come.
SQL, html, C … get things done. When rates go up, these non-bs technologies are incentivized. Paying devs to create new frameworks/apps/products just so that those devs are happy and don’t go work for the competition is what results in complexity for complexity sake.
Those who hitch their success to the latest greatest shiney new bs tech are the same who used to sneer at those who didn’t cover their webpages in flash animation. They make the mistake of thinking the current way is the best way. It’s not old vs young, these two mindsets exist across different stages of the lifespan. Generally speaking, older people have more data and will therefore spot the patterns/cycles a bit easier.
Also, evaluating tooling based on how easy is is to create a "simple hello world" is only useful if your work involves creating "simple hello world" applications, which it doesn't.
One can choose to limit complexity. Nothing is stopping a personal from building things with html, css, and vanilla js.
Think of XHR -> Ajax -> Fetch API or others (Axios).
No one is stopping you from writing out a 20 line XHR request. You can also write a 2 line Axios (or some other XHR-wrapper library) request.
After I took the time study webpack (a day) or reactjs (a month) for example, I really appreciated the options webpack brought (code related plugins), and the structure reactjs brought to my project.
Anytime SSR or any of its derivatives comes into the conversation I always ask myself if things are becoming unnecessarily more complex. React server rendered components sounds like it's taking things too far - it goes against the natural developer experience DX order
If your complexity on the app is doubled and it slows and confuses all the developers with increased coding footguns for only a measly gain in performance, is it worth it?
Good old php sites and rails app with no SPAs have worked fine over the years
The other benefit of such developers is they don't need teamwork. You just throw a feature request out at each dev and they do it end-to-end with you oblivious to the mess that is being created in the process.
"It doesn't hurt to list everything!" - Him
"Why the fuck would someone want to apply to what looks like an absolute hell-hole?" - Me
"But they should apply anyway if they know some of it!" - Him
No shit the quality of applicants is sometimes not the greatest
Or you're on AWS moving toward a more event-driven or serverless architecture where Java doesn't really have the same flexibility (and you don't want to retool your builds for GraalVM)? Go lambdas are really fast and trivially easy to write.
You want substantially faster build times to reduce developer idle wait cycles?
There are plenty of reasons to move to Go.
(Note: I last coded a Java service last year in v17, and my first Java code was using v1.02. I'm no Java hater.)
They have banished AWS..."competitor." A company that can easily justify their own infrastructure (and save a ton of money) is plunging into the Microsoft Azure hot mess. I could go on and on about a lot of other issues brewing there. Very dysfunctional and panicy trying to look hip to investors in comparison to Wal-Mart and AWS. Basically dragged kicking and screaming into online ordering and pickup/delivery and trying to act like it was their idea (very much had/have a browse-in-store sell you more crap you don't need model).
I'm a life long customer of many of their stores and have been plugged into their tech issues via various contacts for about a decade.
First, it is hard to reason about what is happening where (server or client). If you want to know then you have to investigate and most of the time when I'm cranking out code I don't pay too much attention. As he mentions, it is really easy to make a small change and then all of a sudden some large part of your page wants to move from server to client. I know I'll have to do a careful and time consuming page-by-page verification before I finally ship - and that sucks.
Second, many existing React libraries are assumed to run on client because they use hooks. This can drag code onto the client. The whole point of fighting with this new paradigm is that you get server-side rendering which means fast load times and SEO. That is totally wasted if a library you are pulling in refuses to play nice.
Third, there are bugs in the new next.js app directory paradigm. It is still new and it is very complex. Things like dynamic routes and parallel routes and their interactions can just completely break. I've personally filed an issue on next.js github that gained a bunch of "me too" comments. One approach I was taking that was broken was recently fixed by a vercel dev but I had already chosen a new approach to work around it.
The most annoying though, is that their dev setup does some lazy-loading and caching magic. I think they try to compute the differences on a page and send partial updates over a web socket or something like that. It can get completely broken and you end up on an unrecoverable state. Sometimes a re-compile will trigger some communication from the server to the client and when I tab back to Chrome the tab is completely hung and I have to use the Chrome task manager to kill the process.
It is all just very new and in the stage of many rough edges.
Do you mean context instead of hooks here? Plenty of hooks work on the server side, in that they do nothing other than initialize some values.
You're importing a component that needs useState. It only works in a Client Component but none of its parents are marked with "use client", so they're Server Components by default.
There are ways around this, some of which he mentions in the post. It can just get tricky when you are trying to do complex composition.Another thing that hits me is when I have a server component that is marked as `async` and then for some reason it ends up on the client and I get the error that says something like "We don't support async components on the client yet ..." and I have to spend some time looking at my display hierarchy trying to figure out what is causing a client to import it.
It reminds me of the "colored functions" blog post about async/await. You end up with colored components in your app which otherwise look and act the same. But now you have to be careful how you compose them together.
- https://github.com/apollographql/apollo-client/issues/10974
- https://github.com/apollographql/apollo-client/issues/11167
To the point that Lenz Weber( a maintainer of Apollo Client, and my co-maintainer on Redux Toolkit), is considering resorting to a package that wraps and re-exports all of React's public API just to avoid that static analysis:
I think the sleight of hand that is happening right now, and that gets people a little confused, is that React is shaping up to be this thing that handles both front and the backend where other solutions can't do that. Sure – but it does that by overloading and complicating what React once was (neither of which per-se negative, I think it's just an apt description of what is going on)
Where other solutions might have abstracted the frontend part into a thing with a different name (or not bother doing it at all) React chooses in a rather unprecedented move to call it all just... React (well, there's Remix and such, but alas). Which is fine, as long as you understand that this new "React" will now probably lead to "React Frontend Dev" and "React Backend Dev", because the work and the complexities that these rolls entail did not just disappear by rolling it into the same name.
It's not entirely clear if architecturally there are going to be more benefits than footguns, but I think it's cool that they are trying.
Not that there’s anything wrong with that. It’s pushing things forward. (And by forward, I mean, yes, also a little backward. We had server-side dominance with php, etc., then frontend-only with Vue/React… Now we finally get to serve our cake and consume it, too.)
I sometimes hear snarky comments about the proliferation of all these frameworks. But here is the tangible benefit of that “competition.” (Really more cooperation than competition)
The new frameworks were poised to eat React's lunch, they knew it, and they needed something quick to hold back the rising tide.
They may succeed, but only due to inertia, not a better/cleaner solution.
Not really, the percentage of users for Solid, Svelte, and Remix are vanishingly small. They're essentially testgrounds for React anyway.
And when the marvel of AJAX happened I enabled some of the components to be requested separately by the client code, rendered and sent to the client to replace the part of the website they occupied when they were rendered when the page was served initially.
Technically it wasn't client side rendering but it wasn't far from it.
And for actual client side rendering I experimented with compiling my HTML templates into XSLT and sending XML with data instead of HTML to the browser and letting it render it to HTML using provided XSLT. Because it was blazing fast when compared to JS at the time.
So, yeah, I guess thank you industry for coming around to what some twentysomething years old made just to build some websites for his freelancing.
I did the exact same thing. I made a page with a table that was fully rendered server side. Any change in the display, such as pagination, sorting or filtering would trigger the same PHP code that returned a HTML fragment. The Javascript for that was easy. Just send an AJAX request to the server and replace the <tbody> element with the new content.
The PHP code itself was separated in components which made it easy to share the rendering logic for the initial page and the page used for the AJAX request.
React solves this in a more convenient way, but I am really surprised that we had to wait until 2023 before it happened.
It's less full-circle, and more a blob that vaguely resembles a circle when you use are fully zoomed out.
I feel like we lost a lot of time and effort by ditching XML. I mean documenting a REST/JSON API is still painful. While 20, 25 years ago you could already generate your data models and a parser for your XML payload. I still don't know what was wrong with XML. Yeah it was a bit heavier on the line than JSON, but that's a fixable problem - using compression, or use EXI (https://www.w3.org/TR/exi/) to turn it into a binary protocol. I don't know if EXI ever became a thing, but at the time I was quite exited about it knowing how much XML was passed around.
So the tooling nor library support never came for EDI (i.e., Chrome, libxml, etc.)
Also, if you really wanna go full-throttle binary for speed, size, etc., you probably don't want something heavy like XML anyway.
https://en.wikipedia.org/wiki/Comparison_of_data-serializati...
PHP is a phenomenally better language today, and folks really should take another look, but let's not pretend it was always anywhere near as good as it is today. Not by a long shot.
Also, don't judge NodeJS based on the React ecosystem. The sheer mass of APIs and wrappers needed to get a React-based system running is no one's fault but the React community. Stockholm Syndrome at its finest.
Frontend docs sites almost always include runnable examples, that you can play with inside the docs.
Pretty sure Google started / had this years earlier (before Stripe even existed?). And there may have been others earlier as well.
This is a problem a lot of people have; they think in technology instead of actual problem solving. Just look at how many projects have been posted on here with a title like "$solved_problem... in Rust!" as if Rust makes everything better forever.
It's marketing bullshit. It's self-gratification. It's using a technology for technology's sake, not for solving a problem. And it's costing the industry billions in sunk cost, dead ends, overcomplicated and unmaintainable software. Because one guy felt strongly about a language or technology.
Not if you want interactivity in certain parts of the doc site, such as what Stripe does with API keys. It's simply easier to add JS if the entire toolchain is JS.
This is the curse of software developers and employers everywhere tbh.
Edit: downvoters, I'm genuinely curious to hear your perspective.
IMO web dev has never seen better tooling than today, and user experience has improved tremendously over the years.
What we used to call AJAX has grown from a neat side toy to a basic part of everyday life in the form of client components and SPAs. The server is still as powerful as ever if you want it to be. But having such awesome client-side power is nice for interactive apps like dashboards, maps, games, forums, office apps, online IDEs, etc. It enabled the wholesale migration of everyday apps from bespoke desktop apps for each OS to a universal platform across all laptops and desktops.
All that power of course required more complexity. It's very different trying to write a blog or landing page in HTML/CSS vs trying to write a whole web app. Angular and React were invented to help develop apps that were several times more complex than their precesssors, at a time when JS runtimes (and the language itself) were still really primitive compared to the server side languages of the time.
Yeah, there was a really painful period there in the late 2010s where different JS frameworks each solved a tiny part of the problem. These days it's less of an issue. Next won, became the default, and deservedly so. It's really good, and has an appropriate level of abstraction for mid complexity apps, and allows a good mix of server-side rendering and client-side pages. Adding React Server Components makes that division a cleaner first class citizen.
That only makes sense at a certain complexity though. If you don't need it, don't use it. If you're making a largely static blog or documentation site, there are simpler architectures. You can still use HTML and sprinkle in a few lines of JS as needed. You can still use WordPress or Wix for most small business needs.
But if you're building more complex apps, god, React is an absolute dream compared to trying to round-trip every minor interaction to the server for recomputing the UI and sending over an entire HTML page every time, losing context and page position and half filled forms and whatever. It also encouraged the use of form data as state, and work was often lost on an accidental back button or the frequent server crashes before the advent of trivial cloud scaling.
IMO it's only overengineered when misapplied. Some of these tools are really useful, even essential, in the proper use cases. Maybe the sad part is that we overteach them and encourage their use even when they're not necessary (or perhaps counterproductive). Right tool for the job and all that.
Edit: not really pitching React over Vue or Svelte or HTMX or whatever, just that client-side complexity has its uses. Pros and cons, not strictly better or worse.
I have yet to see a React project with more than five contributors fail to turn into a big ball of mud within 18-24 months, requiring either a periodic rewrite or resigned acceptance of trudging through large volumes of mud to get anything done.
(Genuine question, not being snarky)
I haven't tried modern Angular in a while. But Next.js reminds me of a lot of the things I loved about early Angular and disliked about raw React (which always was more of a UI lib than a proper framework). Have you tried comparing them in particular?
I haven't tried Next.js myself though a coworker was playing with it recently. The amount of components available for React, especially the for-pay libraries, can really decrease time to release. But it's still React. Builds a little slower than Angular 16 at this point, but it's fairly close. You still need to keep a firm hand on the codebase when working on a team to prevent code enmuddification, though less so than plain React. React's (what I consider) extreme amounts of boilerplate for doing anything of consequence is still there though. I also personally prefer Angular's service injection patterns over Reacts explicit imports everywhere.
I'd give them both up in a heartbeat for SvelteKit if I could make a business case for either rewrites or new projects. As it stands, Angular is really good enough and fights code entropy well enough that there isn't a business case there yet.
Not my experience at all, and I've been working with React for years. I've seen companies successfully transition to functional components from class components, all while maintaining years-long functionality. Just because you dislike React doesn't mean it's not successful.
I am glad you are an experienced React developer. React needs more of you, because the vast majority aren't.
That said, I have little doubt your and your team's experience could implement with most other frameworks as well—frameworks with a shallower learning curve, just as much power, greater performance before reaching for useMemo(…) equivalents, and far far less boilerplate code.
But 100% correct: I dislike React.
Now if there were a performant version of the core React philosophy like Preact is (or React with their upcoming Forget compiler) I'll gladly take it, but it seems that frontend libraries these days are trending in the wrong direction.
As far as I know, it's not possible to do client-side rerendering without Javascript.
Many frameworks these days do a hybrid approach of server and client-side rendering, sometimes with rehydration, sometimes not. But my understanding is that they all require some level of Javascript to redraw UIs on the client.
If I'm misunderstanding (or just plain wrong?), could you please elaborate?
I jest; our first geocities page was just HTML with maybe a visitor counter, marquee and whatnot.
Our first PHP application / project in school actually didn't use JS yet, it used frames for a static menu and header and just straight form submission to get data to the back-end. Those were the days.
But when I did my first college level internship (1 year of internships is part of college education over here), it was Java back-end, JSX templates for the presentation part, and it was enriched with PrototypeJS for things like dialogs and an animated accordeon (back when animation was still "update the height of this element a couple times a second").
My first job involved using a lot of JS to still enhance a page; add to cart, image carousels, that kinda thing. jQuery era.
And my next job involved building a user interface for customer support staff to look into SAP or something like that, poorly built in BackboneJS.
The next assignment was once again using BackboneJS to rebuild the investment banking front-end for customers. That was - as with most applications I've built btw - a great use case for single-page applications (as they were called then). No SEO needed, fast enough to render purely front-end, API heavy (that was also the time when people realized you could build one API for both web and mobile), etc.
(I'm not gonna claim things were better back then.)
The problem, from what I saw was nested forms and trying to hold state on the client when the server should have been asked for the state. This lead to template duplication and trying to hold too much state on the client.
If the end result was great, I would understand all the effort. But it isn't. React is even slower in real world than the benchmarks show. Next is even worth. I've seen recently many dog slow websites built with Next.
Really, I don't get. If the React team wants to improve React they should fix the core.
The ecosystem has too many dependencies that break at this point. Consider that Target.com, Walmart.com, Microsoft Teams, and untold masses of sites are React.
The huge component ecosystem.
Entire companies built around it.
The core concept is broken§, but fixing it means possibly breaking everything else. If you're going to break everything, might as well use something else.
All we can do is truck along at this point; stuck with React because of the mass of the dependencies.
§ React is the only library/framework that is opt-out of re-render while Vue, Solid, Preact, Svelte are all opt-in. This is one of the core reasons it's hard to do right and prone to a specific class of bugs that rarely -- if ever -- show up in other frameworks as you constantly have to be aware of opting out, even in what seems like normal JavaScript.
const { useState } = React;
function Person(props) {
console.log('Render Person');
return (<span>{ props.identity.firstName } { props.identity.lastName }</span>);
}
function App (props) {
console.log('Render Hello');
const [count, setCount] = useState(0);
const einstein = { firstName: "Albert", lastName: "Einstein" };
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment</button>
<Person identity={einstein} />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('container')
);
The `<Person />` component will redraw on each `increment`. Nothing changed. Why would it redraw? Because when the `App` component redraws, the `einstein` variable points to a new reference. React sees this as a change and redraws both `App` and `Person`. What looks like normal JavaScript here is not. To prevent this redraw, you have to opt out like this: const einstein = useMemo(() => ({ firstName: "Albert", lastName: "Einstein" }), []);
Or know to move the reference outside of the `App` like this: const einstein = { firstName: "Albert", lastName: "Einstein" };
function App (props) {
...
}
Which is fine in this case because there are no dependencies on the component tree. This is the most common mistake I see in React that leads to bugs. It's not just objects, but also functions.This is also a redraw:
const { useState } = React;
function Logger(props) {
console.log('Render Log')
return (<button onClick={props.onClick}>Log</button>);
}
function App (props) {
console.log('Render Hello');
const [count, setCount] = useState(0);
const logConsole = () => console.log("HELLO, WORLD");
return (
<div>
<button onClick={() => setCount(count + 1)}>Increment</button>
<Logger onClick={logConsole} />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('container')
);
Why? Because on increment, the `logConsole` is a reference to a new function. So the `Logger` redraws as well. So here, you need to opt out once again by using `useCallback` or moving the function out of the component tree (fine in this case since there are no dependencies). The thing is that it looks like normal JavaScript but the React render cycle is the unseen; you have to be aware of moving things "out of the way" and "bringing them back" via a hook.React's render cycle re-evaluates entire component sub-trees for changes and if your component doesn't explicitly opt-out by preserving referential equality (`useState`, `useCallback`, `useMemo`, etc.), you'll trigger a redraw downstream. These hooks effectively move the references out of the component tree and pull them back in when the tree re-renders and thus preserve referential equality.
So what teams might do is after experiencing this one time chasing down a bug is wrap every single declaration in a hook to reduce the mental burden. This then creates other issues like performance and memory.
Vue, for example, is the opposite because it has fine-grained reactivity. Nothing redraws until you opt in by using the Vue reactivity primitives.
Im doing mostly back-end work these days to keep my sanity.
Folks want to solve their own problems, but they keep getting saddled with React's as well.
> The pain and suffering of hooks all roots from the mismatch between a dogmatic belief in the superiority of immutability and the harsh reality of the host language that is JavaScript (Feb 25, 2023)
This fundamental misalignment with React and JavaScript is the billion dollar mistake.Try SolidJS. Similar ethos to React but far less boilerplate and performance-killing repaints.
Less code is better, functional or not.
I tried Solid. Signals are not new, I've used Knockout before and it turns into a spaghetti mess after a few years. I guess people today simply aren't old enough or experienced enough to know what eventually happens with fine grained reactivity.
The reason I moved away from Vue is precisely due to the spaghetti nature of fine-grained reactivity. It's like people learned nothing from the reactive stream days during Knockout JS. In a big enough app, the state simply becomes unwieldy and I am always grateful for the unidirectional dataflow and explicit setting of data in React.
UI = f(state), and that's how it should be. useState and other hooks seek to keep state around since at the end of the day we need to make components that perform functionality, and it really reminds me of monads in functional programming. Coming from such FP languages, React was and still is a great paradigm.
There's always some big or missing thing right around the corner... reworking Material components for years, reworking internationalization, improvements to reactive forms, zoneless Angular, single file components, etc. And, for as many bugs as they fight down, it's always felt like there were several obvious frustrations waiting to be fixed. It's all just left me with an impression that the team bit off more than they could chew in creating such a holistic solution and can't quite get to something solid, hence the need to shed things like Protractor.
Hopefully the cumulative effort to improve gets them somewhere and helps get Angular into a more complete and compelling place for folks.
https://react.dev/blog/2023/03/22/react-labs-what-we-have-be...
Jinja2 is better, but most of the time, I would just build the API and not bother with rendering anything on Django itself
Do you mean having a javascript templating system maybe? Not really worth it's weight in gold.
Ruby example that Github is using: https://viewcomponent.org/ https://viewcomponent.org/viewcomponents-at-github.html
Plus if your frontend is react, it’s much easier to keep all the html generation in one place.
It was better in many ways than the dominant techniques in 2013, sure, but that's not a terribly high bar, especially when observing the React model a decade later.
React served well enough for quick starts. It proved… challenging… for ongoing maintenance and quality control in long-lived projects.
complex: 9
complicated: 2
I've tried Nextjs's app router, and server/client components, and there are more footguns and gotchas than you can shake a stick at. Maybe it'll get smoothed out over time, but right now it is downright HARD to keep the mental model of your app when server and client code is constantly being intermingled, imported, and exported back and forth to each other.
I can see the attractiveness to a setup like this. Back when I was much more involved in actually typing out code it was always a pain to switch mentally from backend side coding to front-end side coding. On the other hand, it made it easier to reason about security. Front-end was the wild west and on the backend you didn't trust anything coming in.
Another thing, i understand the supposed advantage of having one language for both backend and frontend but i don't recall that ever being a real issue with me or the teams i worked with. Everyone seemed able to shift from Javascript (and associated Javascript frameworks) to the backend language ( Java and C# in my case) without any issues.
Agreed that switching languages isn’t an issue. But being able to share code between backend and frontend is a pretty nice bonus
The JS ecosystem destroys the past like nothing else.
On top of that, the breadth and depth of its complexity and ecosystem and the solutions it helped build means it's really not going away in a hurry.
Updating a 2013 site from jQuery to Angular was small potatoes compared to updating a site now from react to react2.
Its complexity and ecosystem will be its Achilles Heel. There are no small number of examples of folks rewriting their React apps in weeks or even a weekend in something like Svelte. SolidJS is "close enough" in code patterns that folks will be very tempted to jump ship. Vue now has a JSX option.
But here's the kicker: frameworks like Svelte don't need wrappers around vanilla JS libraries like React has. It can use them, but it doesn't need them like React does due React's VDOM and execution model.
In 2012, jQuery and jQuery plug-ins were everywhere and necessary. YUI was dead/dying. Mootools and PrototypeJS were already quite dead. That inertia couldn't stop React despite the rewrites.
Because let's face it. We love rewriting front ends, and every rewrite erases the past. No one's gonna choose a rewrite in React if they have any notion of the alternatives.
There are 1980s mainframes still running COBOL, especially in older, more conservative industries like banking. Those same banks have cycled their public web front ends literally dozens of times since the mid 1990s.
PHP still does A LOT of heavy lifting even if the front ends have bounced between scriptless HTML forms, PrototypeJS, Mootools, YUI, jQuery, Angular, React, etc.
It's not about programming language on the front end (unless that language is JavaScript, but that's a whole other conversation). It's the implementation of layers on top of JavaScript and the browser APIs, and those will remain rapidly shifting sand for quite some time.
Remember, jQuery had about a decade of prominence in the web dev community before the component-based frameworks were released and fairly abruptly drowned it out. That said, jQuery is still far and away the most popular JS library deployed today.
https://w3techs.com/technologies/overview/javascript_library
React isn't going away, but something else will always eventually take center stage and suck all the oxygen out of the room during new web dev planning.
That it's still in active development with tons of users?
https://blog.jquery.com/2023/08/28/jquery-3-7-1-released-rel...
God, I hope not.
Fixed that for you. I think this is the real reason.
what other options did i have?
Entire companies have been built around the premise of good developer marketing, and if you're faang, you simply get to impose whatever developer trends you want to see in the market.
I'll never forget how wildly popular Stripe became overnight because of how easy their SDK's were - people were happy to give them a higher % of each transaction (all the stripe competitors at the time were cheaper -- this isn't true anymore, but was at the time). It always blew my mind that people were so willing to give up a % of each transaction to save an extra couple days of development.
Developers in general are notoriously susceptible to marketing trends and if you're building a dev tool that you want to gain traction you absolutely have to play that game.
i've tried to produce a lot of technical content, arguing for htmx on its merits:
but the reality is that marketing is what gets people to that content. I tried for years to convince people on pure technical merit alone, and only made halting progress.
i also got very lucky that a few things all came together at once:
* the primeagen & fireship_dev both covered htmx * we released our book * the twitter algorithm changed to boost funny stuff/memes
The propaganda being fed into this industry is impossible to navigate in 2023. The best I can do is to find other engineers who still see things my way and team up with them. I am so grateful to have a few of these on my team right now.
To be clear - Client-side rendering has its place. A perfect example of this is WebGL. But, this is extremely niche when you consider the total space of all business. PHP-style development is still untouchable for 99% of line-of-business web applications. String interpolation on the server was always the answer. Will continue to be the answer until some dystopian organization(s) decide to make it impossible to do things this way.
“Nah, this guy on hacker news said we’re dumb hipsters for adopting the new normal for react. We should stay on the old versions.”
That’s like saying you don’t trust a company because they updated from PHP 5 to PHP 8.2
It’s a fair question. I think it’s a question I was hoping to address in this article, especially with the incremental migration pattern. If you already have a Next.js site, it’s honestly not too bad. If you’re not on Next.js, well, that’s a big migration either way. But considering server components during that migration might not be unreasonable — you’re writing React components either way, albeit RSC is a more complex mental model.
More specifically though: The docs migration took me about a month-and-change of work. Some of that was moving all of our styling to Tailwind. Some of it was (optional) RSC code gymnastics that I mentioned in the advanced patterns section, to see how many kB we could leave on the server. And much of it was the information architecture changes I talked about in that earlier blog post.
Meanwhile, marketing took us three months, but that number is complicated too, since we were rebranding the site, touching every component and page anyways. Most paths had like, 2 minutes of direct RSC work. Moving the calls to the data layer from outside our components to inside.
IMO not bad. In both cases, we had to work on the whole site, anyways. Might as well creep the scope a bit and move to the new React thing, since it looks like that’s where the puck is going.
Another thing, this isn't the first instance of the pendulum swinging back. Providing what would normally be desktop apps through a browser reminds me of dumb terminals attached to an AS400.
My stance is usually that as long as you can get a response to the user (which can be a DOM fragment, a JS snippet, whatever, doesn't matter) within 200ms, you don't need client-side rendering. And if you haven't yet got under 200ms, you shouldn't be spending time complicating your application to be distributed between the client and the server until that's fixed.
I do think this is the question, but the solution is not an SPA, but instant interaction feedback and no content jumping around. If you solve that, a 1-2s response from the server will seem instant, whereas with a bad implementation, you can have everything on the client-side and make that 0ms interaction look more sluggish than the one that goes to the server.
Think of a chat application, if you send a message and press send, it doesn't matter the request takes two seconds, if:
* The message is immediately shown in the chatbox
* There is direct feedback on the status of the message (sent/received/read)
* You can continue interacting with the application while the message is being sent (non-blocking)
You don't have to send all the data/messages before (server-rendered), just some logic to what happens when an action is taken.
It shows a HTTP request made to the company’s publicly visible API endpoint. But this request is being made from their own server (the one that is generating the HTML + JS from these React components).
Is the idea really that your front-end generator calls client APIs rather than internal ones (e.g. just making a database request)? That seems kind of wasteful, and also potentially confusing from a API design standpoint.
It's the same logic why in OOP you have private members/methods. As owner/maintainer of some component you want keep stable public api and be able to iterate on the internals.
Letting any client willy-nilly directly fetch from database is unsecure and unmaintainable in future.
Surely you'd just want to be calling the internal API that the other endpoint is using behind the HTTP endpoint? If you're in the same process (big if, but nothing to suggest they aren't), there's not a lot of sense serialising out to a socket and back again rather than making a function call.
I am not saying everybody needs to do microservices but my experience with monolith is bad. You want at least "some" services and the html-serving service shouldn't usually own the data. User data belongs to user service, report/analytics data to analytics service etc.
Just from the security point of view, the stuff facing internet should have minimum rights to read/write anything. Definitely not direct function-calling or db access.
What concerns me here is mixing up internal APIs with client APIs that are callable from the outside. It just feels weird not to have this distinction when generating pages on the server.
If it's a "front-end generator", we are talking about gerating static HTML, CSS, JS though. This means all "secrets" have to be embedded in client code, or the API calls have to be made at build time, with the static result embedded into the output.
So I don't see your point really.
If your point is talking to a database "directly", using only a database client and no remote intermediary, you can do this in Node as well. And presumably also in RSCs, since it's already possible in SSR.
None of this is prescribed by React.
It's not a bad idea, but it's strange to see old ideas presented as novel.
As Sagan said, “If you want to bake a cake from scratch, you must first invent the universe.”
We’re remixing everything all the time, nothing is completely new and that’s fine. We still move forward.
More specifically though — in the world of web development — some ideas are actually [as good as] original. When CSR/SPA became well established as an approach in web development, there wasn't a time before it when that approach had been common.
The approach to web development described in the article however is essentially the same approach that web developers commonly used 10-15 years ago.
n.b. I'm aware the CSR/SPA approach is more like 20 years old, but I'm making a judgement call on how common common is. Furthermore, when the CSR/SPA approach was first explored in ~2002, what old idea was it a new take on? Flash? If so, what begets Flash? There was a time before the Internet, and it wasn't all that long ago.
This used to be true, but there are new libraries like PandaCSS that bring CSS-in-build-time-JS, thus bringing Tailwind-like performance and React Server Components compatibility. https://panda-css.com/
Seems like he buried the leed, or presumed everyone already knows:
RSCs are ideal when you're pulling data from multiple APIs, some of which may be slower than others.
That said, if the slower one or two are at the top of the page - or at an anchor that might be directly linked to then the UX doesn't really improve, does it?
I'm confused how / why their docs would require React-iviness. Sure perhaps there's a video here or there but is that grounds for tearing down the docs just to use RSCs?
These tools are great, *when they are the right tool for the job*, else we just seem to be reliving an unhealthy infatuation with shiny new object for the sake of my shiny new object is shinier than yours.
I clicked the link out of morbid horror.
The experience of doing these transformations in template languages is pretty sub par.
I hate the scroll hijacking and other shenanigans on modern docs sites.
What I'm wondering is what the anti-React folks are recommending for generating HTML and/or DOM itself in the docs use case, since most of it needs to be dynamically generated from OpenAPI definitions.
Which templating technology would you recommend for the use case instead? Keep in mind that generating HTML from OpenAPI specs can become complex and will require plenty of maps, filters, recursion and indexing into the data in the course of transforming it into HTML.
Are there a lot of server side template languages that can’t do this?
This is straight-forward stuff.
Did I say there weren't a lot of template languages that can do this?
A dead give-away that this subject isn't as "straight-forward" as you think is that, at one sentence in, you've already misidentified the conversation taking place. This isn't about can vs can't, but about the right tool for the job.
What template language would you personally recommend for this project?
How would you approach SSG with Classic ASP?
"The web is too complex! All these web frameworks are too complicated!"
"Okay, what do you suggest instead?"
"I'd just use [completely unmaintainable technology from the 90s that is no longer supported by its vendor]"
"Okay, how would you approach [basic feature of the web framework]?"
"Stop moving the goalposts!"
Come on, you could at least come up with some hand-waving about cache headers and CDNs.
Granted the pages probably wont look as good as what they have here or be integrated in their larger docs, but yea its possible.
But if you are going to build your own docs generator, React and Next with RSC aren't a bad choice. Web development just isn't as simplistic as people on HN seem to think it is.
> React and Next with RSC aren't a bad choice. Web development just isn't as simplistic as people on HN seem to think it is.
Yes it fucking is. I've been doing it for 15+ years and most of the complexity added since about 10 years ago is not required. Many times they're actually regressions.
The web is complex because we made it so.
This is a perfect example where they could write their own docs generator with MUCH less complexity. You read a damn json/yaml file and make HTML out of it. Style it with CSS and you're finished. It's as maintainable as it gets.
Now let's look at running `yarn install` in this project a year from now and see how easy it's going to be to maintain it.
Odds are NextJS will be 5 versions behind and with 500 vulnerabilities found in the dependency graph.
Funny read: https://archive.is/dR1mQ (need to use this link because it is one of those HN-traffic-hostile sites).
If the viewport is 800 px or narrower, click on the menu icon (horizontal bars, top right), then click on a sidebar link. Do that a few times, you’ll notice it’s incredibly slow to react. Same with resizing the viewport, very sluggish.
Some more unhinged stuff I noticed:
- swiping backwards exists the drop down menu for some inexplicable reason
- clicks on menu bar items take so long I genuinely thought I hadn’t tapped on it correctly.
- taps on the menu bar sometimes just don’t work. Like, at all. Oh scratch that, the menu was there after I swapped tabs to write this sentence.
- massive chunks load in at different times: the signing key page shifts as more content loads in 3.5 seconds later.
I am using it in all of my products (non-Rails) and it has been so great.
For CSS-in-JS, those are all 3rd party libraries, so they need to adapt on their side. For example, `styled-components` uses Context heavily, so they need to re-think their approach. For `css-modules` adapting to Server components looks doable, but requires substantial amount of work.
Context is a really nice way to do this.
I'm really sad that tree-specific context for server components seems to be an afterthought. As the Twitter thread suggests, if you have something that can be used across all the server components for an entire request, you can use the cache functionality or rely on Next's URL parameters. But if you've relied on Context as a way to let deeply nested components access some kind of business logic that's specific to only a part of a rendered page, and if you want/need those components to be server components, you'll need to switch to explicitly drilling the props through.
I used htmlx/hyperscript so I wouldnt have to get into JS - I find it a complete headache. Getting the balance between server-side and client side processing so its not a huge pain in my ass to debug also took a little bit of experimentation. But in the end I think I spend more time on styling the webpage with tailwind then on the htmlx/hyperscript which is a breeze to learn from scratch.
Have orchestrated production cloud setups for big tech companies and startups of all kinds of needs, in a week.
It’s been 3 days and I cannot get a value returned from a NextJS route to a React component.
All the blog examples look nothing like the project layout the tools generated for me.
Frontend toolkits are atrocious to work with. Reminds me of Chef/Puppet, solving hallucinated problems to soak up VC funding.
I’ll give it another day or two, because it could be me. But Apache web server, the Rube Goldberg of web software, seems as quaint to use as MS Paint relative to Reacts ecosystem.
read the docs / a basic markdown to html converter would’ve been sufficient for static docs. Worked at a company the completely over engineered their docs. Created some job security for the people that knew how the monster worked, but added zero value for users. Never again
I think most people are scared of what they will find.
That the decades they have spent twisting themselves around frameworks and learning all these abstractions, is not actually necessary at all.
We already have a really nice _declarative_ abstraction in the form of HTML/CSS.
I don't know why we decided to cram everything into the view layer.
Separate your logic into a view model, and then data bind to it.
A simple data binding framework is very easy to write. And then you have full control over everything!
Compare the size of the code below and how easy it is to debug/trace....to the enormous React/Angular/etc. codebases.
const bindings = [] // {elementId, modelId, componentId}
// Allows looking up functions by strings, that are referenced in server-side code.
// Normally we could just reference function objects in memory, but in two separate environments we must use strings.
const components = {}
// Model
////////////////////
const models = [{id: shortId(), count: 1}]
const model = models[0]
// Server-side render route
////////////////////
function renderPage() {
// Create view
const div = createCounterComponent()
document.body.appendChild(div)
// Send this to the client.
const html = document.documentElement.outerHTML
const ssrScriptEl = document.createElement('ssr')
ssrScriptEl.textContent = JSON.stringify({models, bindings})
document.body.appendChild(ssrScriptEl)
return new Response(html)
}
// Client-side main function
////////////////////
function clientMain() {
window.ssr = JSON.parse(document.getElementById("ssr").textContent)
rehydrate(models, bindings)
// Update model and notify view.
model.name = 'goodbye'
onModelChange(model.id)
}
function rehydrate(models, bindings) {
for (const binding of bindings) {
const {modelId, elementId, componentId} = binding
const element = document.getElementById(elementId)
const component = component[componentId]
const {setup, render} = component
setup(element, model)
}
}
function onModelChange(changedModelId) {
const affectedBindings = window.ssr.models.filter( ({elementId, modelId}) => modelId === changedModelId )
for (const binding of affectedBindings) {
const {elementId, render} = binding
const element = document.getElementById(elementId)
render(element, model)
}
}
// Component
////////////////////
function createCounterComponent(model) {
const div = createElement('div', model, createCounterComponent)
return div
}
// Doesn't run during SSR rehydration.
function render(element, model) {
element.innerHTML = model.count
}
// Does run during SSR hydration.
function setup(element, model) {
element.onClick = () => { model.count++ }
}
createCounterComponent.setup = setup
createCounterComponent.render = render
registerComponent(createCounterComponent)
function registerComponent(component) {
const componentId = component.name
components[componentId] = component
}
////////////////////
function createElement(elementType, model, componentFunction) {
const {render, setup} = componentFunction
const componentId = componentFunction.name
const element = document.createElement(elementType)
const elementId = shortId()
element.id = elementId
const modelId = model.id
bindings.push({elementId, modelId, componentId})
render(element, model)
return element
}Why was it considered a bad move to go SPA? I generally disagree with this statement. But I feel like whenever this conversation comes up we're talking different applications altogether. A SPA is fine for a back office application. What it's not necessarily good for is a splash page or marketing page where each page truly operates independently. But in the case of an app that people use frequently, the client side code all gets cached locally anyways, and SSR doesn't buy you anything for that use case. SSR is great for getting a fast time to render on the very first hit to a page. But if you're making a real, rich app, that people will use daily client side JS is not bad at all.
I worked on Trello for a while, it was a single page app with a Node.js API. We served millions of users with it, and people generally loved the UX of our app. But it was a true web app, and not a website. Interactivity was always part of the user experience, and many of the behaviors would be impossible in a pure SSR app.
There are two main advantages of SSR;
- API calls necessary to build the page happen in the data center instead of the public internet, so they're much faster. You can use a database query instead of an HTTP API call if you really want to. That results in a huge speed gain for a lot of sites. It also reduces the complexity of the page - devs don't need to build logic to wait for things. The page just doesn't render until it has the data it needs.
- You don't send the user code they don't need yet. If someone is viewing a page that doesn't have a widget, but you send them the code for the widget because you've bundled everything the site needs into one JS file, you've wasted the users time and bandwidth. SSR is a very easy way to solve that problem.
I'm of the opinion that SSR is a better alternative to a bad SPA, but marginally worse than a good SPA, so for most teams it's a good approach because building a good SPA is hard. If people want to use SSR and that results in me not seeing 4MB homepages any more that can only be considered a win.
The second case is a common misconception of modern SPA. Code-splitting has been around for a while now. When split across routes it's trivial to implement.
For general performance you can cache the modules using a service worker.
In any case they are fine for most use cases.
That's why I personally don't recommend SPAs, it introduce a whole other class of issues on top of what you usually deal with. Google makes it work with Gmail and Youtube but it's Google, they can throw infinite engineers at any problem and could make those in pretty much anything.
I haven't personally noticed the vite/esbuild memory consumption, but I also run build only once at the end before deployment or generating the prod artifacts.
We're using typescript so building only once a day isn't an option.
I don't know what machine you're using, but filling 2.5GB of RAM was already taking less than 200ms back in 2018.
I don't suspect memory usage is an issue here.
And getting more RAM is just delaying the problem anyways since it takes more RAM every week as the product evolves.
During development vite has HMR and you don't need to run build after every change. This is no different when using SSR.
But I don't want to further argue. If you think that SPA is not suitable for your use case, that's ok.
It does reload changes very quickly so I guess it has some caching somewhere.
> But I don't want to further argue. If you think that SPA is not suitable for your use case, that's ok.
I personally never seen a use case which did not end up the way I'm describing, my 2 previous companies suffered the same issues.
I even warned my current company that there's a good chance that it would end up the same way and sure enough it did.
Reddit is probably the most familiar example of this, because it actually has multiple implementations (old.reddit, i.reddit etc) that let you see the difference!
As for whether the initial paint is of value, that comes down to product and implementation. Nothing is faster than offline-first or local cache, which SSR does not have a good narraative for.
Thin client vs thick client has been a point of contention since mainframes and minicomputers.
Surely they are getting done on the server that hosts the API? Unless you are using something like Firebase or SupaBase which can sort of enable client side database access (but not really, it’s still doing it on a server, just their server and running the call through RLS or similar)
(but yes, we have unusual customers I guess)
Just saying: the generated HTML could be a lot larger than the Javascript generating it. Usually it won't be, but it's not a given that sending the HTML is less bandwidth.
Devs don't need that anyways, since frameworks like Angular provide this ootb, may it be dynamic template renders (ngif) or as a prereq for finishing routinh
Clearly if your website essentially just retrieves some data and displays it to the user, you can use SSR. It seems most frontend discussion - and even most of the frontend dev velocity - focuses on this context.
Other common advice is "you don't need global state mgmt - use component state and a query library with good caching". Nigh impossible to retain performance and high interactivity without redux/mobx/etc.
It's very empowering to be able to create sophisticated web apps that run on any device with a web browser! SPA is a very valuable pattern.
It's considered a bad move to use SPAs because product managers tend to err on writing an app when they should be writing a site; the reverse rarely happens these days.
Trello is probably an example of an app that worked with SPA. But the other perspective of this is that people weren't sensible about using React, they tried to use it for everything, they got onto React because they could hire for a very discrete front-end role and then split back-end, very few companies did this sensibly. The big problem with React was really how people used it, and this seems to have guided the development efforts on the project.
Btw, the move to SSR is already having operational issues. I have noticed companies hiring now for "full-stack React" because they hired a lot of front-end specialists who don't know anything about Node and won't learn it...so I think the issues with hiring will continue.
That line was a fun, sassy one. And probably a bit too strong. I definitely meant to temper it with the next few sentences.
> Sure, it’s simple, which is worth a lot! … And for frequently changing, highly interactive pages like a dashboard, it’s probably enough
I spent years working on a medical dashboard SPA and we never once seriously talked about SSR. They totally have a time and a place for web apps. I agree with you and I’m glad you brought it up.
I’m sure they’ll claim it’s different now because… hydration or something or another.
As a former PHP developer who spent a lot of time both working on server rendered pages and converting server rendered pages to be API/JS (render the core in HTML+JS and use APIs with two way data binding to update the UI), I can’t believe we’re going back that way, but with wildly more complicated patterns than we had before.
I just wish we had skipped all the in-between stuff and just arrived at htmx back in 2011 instead of now. Maybe I'd still be doing frontend stuff and not burying my head as far into backend as humanly possible while I wait for a workflow that doesn't require a package.json and a 3 GB node_modules folder so I can make the same frontend widget I could make with 50 lines of js in 2007.
We kind of did (well, 2013), but it just wasn't backed by a massive developer marketing effort.
It feels like the end state here is going to be HTML+CSS with JS for interactivity using APIs, which is exactly what I was doing in 2006.
It’s all JS, which we know from the frontend, all that "magic" is done by the framework in the background. You write it once, it works both ways automatically.
We already build 3 webapps using SvelteKit, still happy for the ease of use, or great "DX" as some call it.
I remember writing PHP and JSF back in the 90s and 00s, and the experience of both writing RSC and Next.js as well as using websites built with these technologies is simply not comparable.
Also, I recall heavily using jQuery and Ajax to update parts of the page before Spa’s came along.
People want that back, but they also like React, and their existing component libraries, and they want to generate the backend pages with React. It's not that strange.
And you can (I think) pretty seamlessly have part of the page rendered on the server, and parts still function on the client.
Is it because these devs can only do React and nothing else, so we will shoehorn everything into it?
I mean, more power to them, if they want to do it and have 10x the complexity and take 10x longer than learning and using normal, already available tools.
The server side components didn't seem to me at a glance significantly less convenient then say a normal PHP server stack.
Modern SSR implies just do simple rendering on the server and hook it up with simple tools like Htmx, Turbolinks, etc.
Keep the complexity accessible on the outside, like the Pompidou Centre.
Why not use already battle-tested CMS solutions (opensource or paid) and focus your dev effort on your actual product, in this case a video platform product.
What drives this behaviour? I mean the question on a deeper level. An answer like "the technology hype cycle" just begs the question. Why does someone feel like they have to move business logic onto a particular framework (and then realise it's a mistake and move it again to a different framework that's similar to the one they started on?)
People (rightly or wrongly) believe the new technology is better suited to their problems.
IMO I think that's at least part of the issue.
There's also the common notion that movement seems productive. If you are not moving, what are you doing? This effect happens on a lot of levels. Especially managers have to show they are moving needles. Any movement is better than no movement.
Because only the tiniest, most incremental changes can be made to the browsers, and because there are fundamental native/universality conflicts all the time, making tiny improvements to UX requires huge behind the scenes troop movements. And then it's subjective, so maybe it just makes the UX worse in the end.
UI frameworks seem to be surprisingly hard conceptually. Neither Microsoft nor Apple have really proven that they can do better when on a field entirely under their control.
Not to mention business model considerations, such as the worsening of Reddit.
You have a backend service, you implement it in whatever language you want, presumably C++ if you care about performance or are doing something non-trivial. It provides REST and WebSocket endpoints to input and receive data.
You have your GUI to visualize the thing. Common sense is to have the overall structure in HTML and fill it in with JavaScript that queries the backend. The advantage is that you have a rapid and interactive development environment in the browser and can quickly iterate on a useful GUI without touching the backend.
Then, moving the GUI to be part rendered on a server, that sounds like a terrible idea, a good way to increase latency and to add load onto your servers. If you need to do that to get decent performance then probably your backend API is inadequate.
Compiling the code also breaks the whole point as it makes the development non-interactive.