A tale of webpage speed, or throwing away React
solovyov.net
solovyov.net
First, keep in mind that the author's use case is a content-heavy app with sprinkles of interactivity. This is very important because it sets the "webpage speed" goalpost to a concrete place: they want good lighthouse/first load times and good SEO.
I've fallen into the same pit before. I've used Create React App with a custom server-renderer, Gatsby and Next in different projects. None of the solutions is truly satisfactory for the author's use case for a single very strong reason: React's hydration process is both blocking and slow. I hope that sooner rather than later React is able to offer a good solution for incremental hydration, but it seems quite far for now.
Once you realize this, the only way to keep using React is to step out of the mainstream and play with multiple render roots, parts of the page that never get hydrated and so on. It is possible to do things here, but it is definitely a rocky path.
Of course, there are many wrong things the author explains that you can avoid, but I'll throw a bone to them here too. Most "wrong things to do" they explain are both wrong and understandable. And they openly accept it.
For instnace, one wrong thing to do that I've had to fight against a lot is JS-based device-specific rendering. It is so much easier to implement a "mobile ? <MobileScreen /> : <DesktopScreen />" than to make a single screen that adapts properly using CSS that it's not even funny. Unfortunately, it also breaks SSR, leads to janky page-loads and poor performance.
I fully agree that as of today and for content-heavy sites React pushes you towards a pit of despair instead of a pit of success. You can make it work, but ... is it worth it?
This depends on project size. If a single team is working fullstack then using server side templates gives seriously faster product development iteration. Once you get to more than 5-10 devs and you want separate frontend and backend teams then it slows down.
It’s backend-agnostic.
NextJS is something that folds over some of this, but it's not without its issues.
Of course, no better way to find out than try it for yourself. When I have the question of "why don't people just do X?", trying X myself is a quick way to realize why, and unfortunately it's never because I'm the first genius to have thought of it.
But something similar but not the same as that was the norm during the jquery era before the early js frameworks arised (backbone, ember et all). You had your full-stack server-side MVC framework render initial views and from there the js would pick up and all UI interactivity would be ajax calls to the restful(ish) api. It was pretty terrible.
Because this introduces clear separation of concerns? You don't need to make this API call via HTTP, you can just call a function. You don't even need to generate/parse JSON!
I know that because this is what we are doing. Just calling a function called "httpapp". :)
Around the time the first js FE frameworks came out, people finally became confident enough to have pure js clients and only json APIs.
And finally gatsby, next.js, etc. brought a new twist to the SSR and Ajax api combo.
Long term I think we'll eventually see the ability to interact with the local system via the browser, and we'll start seeing more things like "QT for the web".
Because if we don't, at some point it's all going to just fall over.
I don’t need more types of semantic rectangle, I need actual real UI controls that are efficiently rendered and accessible by default, so I don’t have to build everything from scratch.
The fact that there’s no built-in element for things like dropdown menus is mind boggling to me. That’s GUI component #0; menus have existed for as long as GUIs have!
I feel that Houdini may eventually solve CSS’ shortcomings for application UI layout, but being stuck with HTML is like trying to build an aeroplane with sticks and mud.
You mean the select tag?
Huh? Something like Rails lets you iterate on server-side stuff extremely quickly. There is a lot of functionality you can implement that doesn't need JS at all
As for web app vs web page--it's a very blurry line, and it's rare that I end up building something where the entire site could be considered a web app. Usually only some small pieces of it demand enough interactivity to bother with the complexities of using a UI framework, and for that I wrap a small React or a Svelte app in a div and throw it on a page within the larger site.
you would think so, but there are an awful lot of people don't seemed to be stopped by that
* composable templates
* reusable JS snippets
* hot reloading in your browser
And additionally, given that the topic is "building web applications", I can't really understand how you think you can build interactivity without JS. Are you proposing form-based updates or is your understanding of "application" different than GP and mine?
https://guides.rubyonrails.org/layouts_and_rendering.html#us...
There's no standard way for handling hot reloading, but there's a bunch of recipes on stackoverflow.
We recently added this "feature" to our react-on-rails codebase, and the only thing I can ask is... why?
Hot reloading on Unreal Engine is a hot mess with all sorts of little caveats to think about. Meanwhile I can hit F5 and as long as my browser is configured right I can guarantee there's no old cruft to deal with. Why in the world would I want to add that kind of uncertainty in my work codebase??
The analogy I like to make is this: imagine a painter had to wait 3 seconds for every stroke they made to show up. Would they be as good? Would they try out as many variations? Discover new paths they could go because they had the time to “test that weird idea real quick a few times”?
Hot reloading works especially well on React (and not I assume on game engines) because React, with hooks, used algebraic effects, which means all side effects are properly understood by the system and are undoable. So it’s not as hacky at all as you’d imagine.
I never understood the hate for HMR as a concept. Perhaps your implementation wasn’t great, but as a general concept it’s literally a game changer.
The same people who cast shade on it seem to always embrace incremental compilation (like in Rust) for some reason, too.
But I also think this lessens the requirement for a solid mind's eye and ability to visualize changes before you make them. Having come from desktop development (with "live" gui development kits like VB) into webdev I guess I got used to code-a-bunch-of-stuff-and-hit-reload pattern.
As long as it doesn't get in my way, I'm cool with it.
Most web-thingies are neither 100% plain websites nor 100% plain webapps, most are in the middle, some are heavily leaning on one side or the other.
Since we're tackling similar problems, do get in touch with me if you want someone to share ideas with in future.
1 : to cause to take up or combine with water or the elements of water 2 : to supply with ample fluid or moisture
Maybe I'm old school but the word "populate" makes a lot more sense than hydrate when talking about data.
Same idea, only for objects. You hydrate them by adding data.
The term has been used for probably 20+ years.
I've no idea of the etymology for this or why this conflation is surprisingly so deep in contemporary English culture, I've just been fascinated by it for a long time.
I have recently started using gatsby-plugin-no-javascript. It's a very crude version by removing hydration at the page level. It works pretty well for me because my site is a ton of static pages and then one very interactive app page. I get to build it all in React, get a great developer experience, and then all those static pages are like 20k total (css, images, html, everything) and load in the browser instantaneously.
If we could get this ability, but be able to apply it at a finer granularity than pages, we could probably do some really great things.
Thank you for mentioning this! I’ve been on a passive search for exactly this: the ability to use React and generate a completely static site without even the possibility of JS at runtime.
Example: I have a stack of boxes of varying heights. On mobile they are fine as is (one below the other). On tablet I want them in two columns but displayed in column order without gaps. On desktops I want three columns. This is dynamic data, so the number of items and their heights will vary, but my CMS allows the user to mark at which box(es) new columns should start:
mobile tablet desktop
a a c' a b* d*
b* b d c
c'
d*
' indicates this element starts a new column for tablets (two-column layout)* indicates the element starts a new column for desktops (three-column layout)
Can you achieve this with HTML/CSS alone? How?
- CSS columns won't work because Safari doesn't support break-brefore in a columns context.
- Flexbox won't work because you don't have a defined height for the container (so you can't use flex-direction: column + flex-wrap).
- CSS grid won't work because you'll get a grid (i.e.: gaps between elements when the boxes have varying heights).
- Ye-olde-floats won't work because you'll get weird gaps too when the sizes change.
- You cannot wrap the elements in column-divs because you can't do it for both tablet and desktop simultaneously.
Also, you need to be very confident in all of the above to know that is is not possible, instead of getting sucked into trying, getting to an "almost there" point and then realizing it doesn't work under X condition.
In contrast, with React you can just generate 1/2/3 wrapper divs depending on whether the current width is mobile/tablet/desktop and call it a day. It takes you all of 5 minutes to do so and the margin for surprises is 0.
Edit: reworded why flex won't work to address nawgz's comment.
Are you saying the issue is that flexbox will force everything to have the same height? I am relatively sure that `flex: 0 0 fit-content;` on the children and `flex-wrap: wrap; flex-direction: column;` on the parent will do what you want
No, I'm saying that you will not get columns unless you specify a fixed height for the container. Since you don't know the total height you want for the container, this is not a valid solution.
However, if you're already using wrapper divs, it seems to me like you do some math on your boxes after the initial render to balance them. Either that or you literally just group them into 3 groups and accept whatever artifacts (read: column height mismatches).
Either way, there is a CSS-only solution of sorts. Render the parent with 0 height, iterate over the children groups to find your max column height (remember - you already do this grouping with your wrapper divs), set your component height to your max of the 3 groups with 200ms transition, and you have a sweet CSS-only animated solution
Might not be worth it - in my approximation it's not - but I guess that could depend on your domain.
https://developer.mozilla.org/en-US/docs/Web/CSS/order
Also if css can't do it why go you need react when you can do it in few lines of css? Not not difficult to rearrange elements based on viewport size.
That said, I also don't have to support older browsers. We're content heavy, but traffic is so small from Safari, older IE, etc. so we're fine with using newer features.
So out of hand. It feels like Javascript webdev is recursively devouring itself into a completely separate type of programming.
The idea is not that complicated:
1. You send the page's full HTML to the client. This is good for SEO and to quickly get the page to show. This HTML has been generated by running React on the server and capturing the output.
2. You send the React stuff (React itself, your pages components, extra libraries you are using, etc.)
3. You hydrate React's virtual dom using the already existing DOM (that the browser has created in step 1). This essentially amounts to telling react to attach the proper event handlers to the DOM so it can continue working as if that DOM was created by React itself.
ReactDOM.hydrate(element, container[, callback])
Same as render(), but is used to hydrate a container whose HTML contents were rendered by ReactDOMServer. React will attempt to attach event listeners to the existing markup.
Searching for hydrate in the React docs leads you to the hydrate method, which describes itself in terms of its use to hydrate a container. The crazy thing is that there's numerous blog posts that purport to tell you what react hydration is, which do the exact same thing and define it in terms of itself. Partly, this may be React (and the community's) reliance on you knowing what that concept is, but that's particularly unacceptable in article that purport to explain it.
Is it really so hard for these reference docs and explanatory sources to say something along the lines of "hydration in React is the act of fleshing out a server delivered model of the page that came with poor or no data with rich data delivered later in the process" ?
[0]: https://www.doctrine-project.org/projects/doctrine-phpcr-odm...
I will say, hydration in the context of an ORM seems fairly odd to me. My concept of ORMs doesn't mesh well with the need to pre-populate of bunch of template which you fill the data in for, since I think of them as pretty much all data with some behaviorioral added on.
I guess it could apply towards auto-fetching data as you traverse relations, but those don't exist in a skeletal form AIUI, they are created as needed when requested and data is queried (that is, there's no structure to hydrate with data after the data comes back). I guess you could create objects, query data, and then add data to objects, but given that you often don't know how many objects you'll need, I'm not sure how beneficial that is.
Then again, it's not like I have enough experience with the concept to know the nuances of how it's bandied about.
The page that he browser is hit with has ALL the content pre-rendered (sans CSS) in that first HTTP HTML response, and it behaves like a classical webpage henceforth until the moment that the interactivity bits are being hydrated which is deferred.
I concur that it's still a bad idea to use SSR SPAs for use-cases where a non-dynamic HTML page would work decently well, and there are ways to pack some of these frameworks (Vue in particular) so that it's a JS dependency of an otherwise functional webste (i.e. progressive degradation) for a lot of the in-between use-cases, but when what you're building is heavily leaning towards being essentially a web application (say, an e-commerce site, webmail client etc) then SSR is certainly the most viable option for a decent user experience that isn't full reloads on every click, but also doesn't take ages to become interactive.
That is what Gatsby / Next.js do too. The issue is that deferring the hydration doesn't mean it is neither non-blocking nor quick. Once hydration is triggered, the browser gets blocked until it finishes. Of course, the speed of the process depends on the site and how much content it has. If you are building an e-commerce site, this will tend to be on the side of heavy (just the full menu structure, footers and such will be quite a lot already).
> but also doesn't take ages to become interactive.
The issue is that a regular old website can be interactive almost immediately. If you have a hydration process interactivity is inevitably delayed for any part that does require javascript to function... and also for the parts that don't, because the browser main thread is blocked for a while doing the hydration and won't respond to your inputs until it has finished.
If you don't believe me, open an incognito chrome window without any active extension, go to nuxt's own documentation site [1], run a lighthouse performance evaluation with the default settings (mobile/simulated) and see what scores you get.
In my laptop it is a 33 overall for performance, with 4.1s FCP, 9.2s TTI, 6.1s LCP and a total blocking time of 2.41s.
You can also test from https://web.dev/measure/, where I'm seeing a 57 overall (much better, but not good) with 3.5s FCP, 7.8s TTI, 4.9s LCP and a total blocking time of 500ms.
That is, the creators of this software have built a documentation site (i.e.: mostly text, very little interactivity) that doesn't get good performance scores. This, along with blogs, is the best use-case I can think of for the technology. And it doesn't perform good (according to Google's-defined objective metrics, not mine!).
I realized that I could just deliver and slam HTML into the DOM and that the browser engine, written in C, was very fast at rendering it.
That turned into a pretty big javascript function, which then turned into intercooler, which then turned into htmx:
Tools like this feel very familiar to those of us who got started before the rise of the modern JS framework. It's kind of fun to see articles like the OP's pop up where people are rediscovering these techniques.
The problem is that HTML was never completed as a hypertext, they just kinda stopped at anchor tags and forms.
There isn't a good reason that only anchors and forms should be able to specify HTTP requests. There isn't a good reason that only clicks or form submits should be able to trigger HTTP requests. There isn't a good reason that only POST and GET should be readily available (and POST only for forms.) And there isn't a good reason you should have to replace the whole page on every HTTP request, rather than a component within it.
htmx is an attempt to complete HTML as a hypertext.
There isn't a good reason that only anchors and forms
should be able to specify HTTP requests. There isn't a
good reason that only clicks or form submits should be
able to trigger HTTP requests. There isn't a good reason
that only POST and GET should be readily available (and
POST only for forms.)
That's an excellent and thought-provoking way to think about it.I'd always been mentally locked into HTML's basic "the web is a series of linked pages" paradigm that was in effect ever since it debuted, thinking that to do anything outside of that paradigm you'd obviously want to resort to manipulating the DOM directly with javascript.
But, there's really no reason for responsibilities to be divided in quite that manner. There's really no reason HTML itself can't encompass somewhat more robust hypertext features, with declarative support for functionality like "this link should load URI abc in the xyz region of the current page."
Frames, of course, did sort of do that natively in HTML, but that was a very clunky implementation to put it mildly.
I can think of potential arguments against what you say, but I think I agree...
So with htmx I'm trying to complete the HTML hypertext and let people take advantage of the simplicity of the REST model without sacrificing user experience.
Once I got past certain mental blocks, it became fairly obvious that you can structure all your GUI scripts to be configured and to interact with one another via DOM.
The next insight was to use CSS selectors for targeting.
Then using consistent name prefixes and separating behaviors into self-contained libraries.
The stuff above was proof-of-concept. The possibilities behind this approach are mostly unexplored.
If you ever need to switch away from intercooler you are going to have a large undertaking not just on the front end, but now on the back end as well.
But I might be missing something.
Intercooler is great for some cases and can make a good transition step moving from all server-side v1 to a fully responsive/dynamic v3
EDIT: I should have read your comment more closely. With respect to two end points, one html and one JSON: I view the JSON and HTML end points as separate problems that both benefit from not being conflated with one another.
Your HTML end points are tuned to the particular use cases for your UX (e.g. active search) with the caching and tuning required for your specific needs.
The JSON end points need to be general and support unknown 3rd party client needs, and thus require more expressivity (e.g. GraphQL) at the cost of not being tuned for particular use cases.
I tried to get this idea across in this older blog post:
It's trivial in most web frameworks to have an endpoint respond in two ways, one with all the html including head, menus, footers, etc. if you hit it with a GET, the other just the snippet if you hit it with an Ajax request.
A REST API is basically a massive over-complication unless you actually need it for a good reason, say you're running both a web app and a mobile app from it.
I've used this technique occasionally for over a decade and personally have always found this server-side approach very simple compared to juggling REST APIs with client-side rendering when a client or an existing code base demanded it.
I've also always found the defence 'you might need to switch' to be a flimsy one. Usually when you do need to switch, everything is so different even your 'future-proof' API design needs a massive overhaul too because you made assumptions you didn't even realize you were making.
Think of all those SOAP or XML APIs that were future proof...
I mean I switched from jQuery to knockoutjs to react all on one application and the API served all those transitions well. So I'm speaking from personal experience here. But that is anecdotal and maybe it's not typical.
For example, if I have search functionality at
/search
and I'm implementing the active search pattern shown here:
https://htmx.org/examples/active-search/
I'll re-use the /search url for the partial search results and check the HX-Request header to determine if I want to render the entire search UI or just the search results.
If you use hx-push-url as well, you can get a search dialog that acts like an active search for the user, but also retains copy-and-paste-able URLs
I think you're talking about the difference between an "experience API" - that is, an API with the sole purpose of being support for user experiences/clients - and a "system" or "process" API, where the latter is for application or process integration between many systems. These are terms borrowed from Mulesoft, but I do like the terminology, I find it helpful for segregating concerns.
There are a lot of reasons people need separate experience APIs to power specialized UI/UX - especially with the needs of different client platforms (ex. chat bots vs phones vs desktop browser), separate from system/process APIs.
This is ok, adding an endpoint to spit out html is super simple, it's just printf statements with angle brackets.
Beside that I find endpoints need to be somewhat coupled to the UI anyway, otherwise the endpoint needs to be a superset of all possible data and all the complications that come with that.
https://htmx.org/examples/active-search/
Htmx can be used to implement reactive components, however. Ben Croker created the Sprig component framework based on it for Craft CMS, for example:
At a glance through the docs, I'm pretty sure I can replace about 30% of my website's javascript codebase with this. Not to mention that having to actually write the javascript to "spruce" up a form will often lead me to be lazy and just have people deal with an un-spruced-up form.
I'm itching to get off work and try it out for real :) Thank you for all the work you did on this.
I stuck a 300ms delay in the mock server to make it seem a little less instant:
view-source:https://htmx.org/js/demo.js
I didn't want people to think I was misleading them about what was going on. I would typically expect a simple edit form to return in sub 50ms.
I do agree here. Also, if you’re careful about it it would be really easy to just scale the shit out of the document builder, add caching, etc.
Looking forward to following your project, it’s very interesting to me!
I had one quick question - how easy/difficult would it be to integrate another JS library with intercooler or htmlx. For example, let's say a table is fetched dynamically via htmlx, how would we go about integrating a library that does client-side table sorting/filtering?
htmx.onLoad(function(content){myJSLib.init(content)})
React is a great choice for certain use-cases, but when low-quality developers are allowed to pick it up and apply it to everything you end up in a mess. The same thing happens with literally any tool.
If you want speedy initial interaction times and manageable codebases, (and requirement X) use the right tools for the job, and instil better, thoughtful, development culture.
While the reality is more like this: I had 6 months of programming experience and used jQuery and made a disaster; with 1.5 years of experience I used Backbone and I fared better; with 3 years of experience I tried Angular and I was able to build a decent size application but ultimately shot myself in the foot; and now that I have 6 years of experience my software quality has improved a lot, it must be react!
I rarely see any decent architecture survive growth and real world use beyond a couple years. It's usually either 1) "no one could possibly have foreseen this new use case/requirement" (from less experienced folks) or 2) "YAGNI!" when trying to build in some abstraction levels to handle use cases you know will happen down the road.
There's a tendency to blame the tools. You can build a big, high quality app in almost any language and framework.
If your mindset is persistently "this framework/tool will solve all our problems" you're always going to have a bad time. Understanding the pros/cons of each element is essential to becoming a good developer.
IMO UI is generally something new programmers like because of the visual/visceral "I built that", but once you get exposed to the sheer annoyance of UIs, programmers will migrate to backend.
So the most experienced people don't want to be constantly undercut in price by the incoming "talent", realize that WebUIs get chucked every 3-5 years anyway due to browser tech churn, and move to data monopolization.
API generators had the same thing. Strongloop was a decent frameworks before they started throwing 10'000 juniors to fix issues and made a mess of the codebase. If you look at the jungle the React codebase is and you compare it with Preact (it's smart, concise and performant) you'll understand why code quality matters. And I'm not talking about stupid metrics.
Carefully picking tools is important, but also, don’t adopt more tools than you need to.
One common example I have seen is pulling in a CSS-in-JS library to do something that SASS can easily do... when SASS is already incorporated into the build process.
SASS offers a fairly complex set of features if you care to learn about them, and the module system (in development) is going to solve @import global scoping issues very elegantly.
I don't think it's worthwhile to minimize the actual, useful impact React has had for web apps.
Slowly we are rewriting individual pieces as embedded React components (no SPA here) and moving to a proper API layer that the components talk to. The separation of concern has made it a loot easier to increase code coverage and ensure a controlled rollout of new features.
We also just bit the bullet and paid for syncfusion to use on our frontend to avoid reinventing the wheel for a lot of the functionality we need.
Maybe stability? Besides Semantic UI I found that other frameworks are nowhere near as mature. I guess if you're a big company its a small price to pay but it also seems like you're paying a grand + per month for something with tons of free alternatives.
This can be achieved (and more easily) by separating your templating from your business logic at the package level. If you know what you're doing you can keep things separate and your import graph non-cyclical, if you don't know what you're doing you're going to recreate the mess in your components and API anyway.
Source: Tired of seeing this happen again and again and again and again. And fixing it.
Since we need to also provide an API going forward to our clients, for our usecase this was a great solution. However we are not doing an SPA, the main framework and navigation is still server driven. The difference is that the "create new user dialog" is now a react component that calls the corresponding api.
Running through the API also makes it easier for us to handle the caching of data at that layer instead of a mix of jquery calls and random div HTML generation.
This is some strange reasoning that I have yet to seen myself. If you can do the hovers states/drop down menus in CSS, why not do them in CSS, even if you're using React? Seems to be blaming something on a library that the library has no care about in the first place (which to be frank, seems relatively common in web dev circles).
> In the worst case, we would serve you 2.5MB of minified (non-gzipped) JS
And holy guacamoly, how do you end up with this?! Seems that something was surely wrong in the compilation options, forgetting to mangle names or something, missing dead-tree elimination maybe?
Don't think that matters. I've written (from scratch and inherited) and deployed many ClojureScript frontends, from one page ones with lots of interactivity to 30+ pages/sections, none of them reaching the size of 2.5MB minified (when using the production settings for Closure Compiler). Add in SSR and/or code splitting and the weight should be nowhere near there, leading to the guess that something is wrong in their config or they are embedding binary files into the JS asset.
Okay, so how about not inventing outrageous ideas on the spot and just consider what is written?
It's equally as hard to unload what's been boiling in your brain for last half a year. I'm reading comments and trying to decide where to expand my post, of course, but this "binary" thing just got me laughing.
EDIT: I mentioned webpack since the thread is about react, but you can do the same thing manually by putting the base64-encoded data in a data URL on a CSS file.
That said, animation is hard, and React doesn't insulate you from that, so it takes some thought. In fact, being a layer of abstraction, it requires even more understanding of animation. Fading a component in is easy with regular CSS transitions. But fading a component out generically means that you have to keep the component mounted for the transition.
Perhaps anyone who has used react-bootstrap's Transition system (animate={true} on modals and tooltips) has run into those quirks where you start seeing a pattern of animate={false} fixing all sorts of random bugs.
With React, if you're grabby with 3rd-party libraries, you can end up with a russian doll of HoCs, each one from a different library, that are so generic that they kill performance and it's not even obvious why without being a profiler expert. Whereas without React, you wouldn't have found those solutions at all, so you roll your own cross-cutting solution.
That isn't necessarily a problem with React, but something that you have to resist with frameworks in general. It reminds me of Ruby on Rails, googling "rails avatars" and ending up with two libraries like carrierwave + "has_avatar" when you could have just built your own simple solution. It's a form of technical debt. After all, it's hard to justify the effort of deabstraction when you're assigned to 100 other issues.
Before then you could only do animations with Javascript, and frankly jQuery's `animate()` was a god-send.
Is there ever a real reason for animations that doesn't make the interface feel sluggish and unresponsive? In the other hand if you actually set the animation delay to something incredibly low, all of your animation needs could be easily solved by animating the transparency of the appearing elements.
If you start paying more attention to the apps you use, especially ones made by bigger companies, and you'll notice how effective some of them can be.
I don't think it is. And it's from a company which can afford a lot of development resources for that.
The takeaway here is twofold: we need better tooling as well as better practices for how to use those tools. It's both an educational problem as well as a toolset issue. It is possible to build lean and fast pages, but it's currently considerably harder than building gargantuan monsters. I don't see the web bloat problem going away until the dynamic here is flipped — it should be easy to ship small bundles even with minimal experience.
Still better than C++ standard people who try to cram infinite complexity into 100 layers of templates every three years for sake of adding a feature as library instead of language feature, with utter ignorance towards debug build performance, compile times and error messages. I have lost respect towards them since I read a C++ performance report and didn't see the mention of inherent STL inefficiencies.
Our designers wanted to add some SVG animations, they started off with Lottie (https://bundlephobia.com/result?p=lottie-web@5.7.2) because they could export directly from After Effects, but I said no chance because of its file size. Briefly considered Greensock (https://bundlephobia.com/result?p=gsap@3.5.0), but it was also too big for the kind of animations we were looking it.
I'll need to double check what we ended up with, but it didn't have any library code, so each animation was just a self-contained bundle of SVG and CSS animation code, and fairly small.
Edit: I asked around and SVGator (https://www.svgator.com/) is what we ended up using.
You start out with good intentions, but after 4 years of different people certain parts of codebase start looking really weird even with code review. You just can't catch every little detail.
And this is why tools should make it easier to do good thing (good as in what you'd want to see in the end).
That's pretty much how software development works though. It's what happens when people with varying skill levels, schools of thought, preferences and approaches to problem solving all work in the same code base. Heck, it'll probably happen even if it's your own pet project: four years is a long time in something as fast-moving as web development, especially when you factor in things like market-driven priorities (E.G. adding new features vs. fixing old "good enough" crap kicking about).
I honestly doubt there's a single software project in history that doesn't have shady corners after a couple of years, no matter how excellent their frameworks, conventions and developers are and how draconian their review process is.
I did not decide to switch from React with a light heart, it was a long and painful decision. But it seems to me that React's path of least resistance leads to a slow bundle, and you're going to fight an uphill battle.
Let's all be honest, that's complete laziness or lack of knowledge by the developer.
> And holy guacamoly, how do you end up with this?! Seems that something was surely wrong in the compilation options, forgetting to mangle names or something, missing dead-tree elimination maybe?
Maybe sourcemapping?
Libraries and frameworks establish idioms, which encourage or discourage certain patterns. In my experience React / JSX definitely encourage complexity and abstraction by making display and logic so intertwined, especially with hooks.
> And holy guacamoly, how do you end up with this?
Libraries upon libraries, one tiny problem at a time. Unless you're in a very small team, or have very strict policies for adding new dependencies and vetting their impact on bundle size, this will inevitably happen.
<Button styles={[...]}
onPress={() => setState('active')} />
const styles = StyleSheet.create({
active: { backgroundColor: 'purple' }
})
progressing into: <Button styles={[...]}
onPress={() => setState('active')}
onHover={() => setState('hover')} />
const styles = StyleSheet.create({
active: { backgroundColor: 'purple' }
hover: { backgroundColor: 'blue' }
})
which is frictionless and 'clean', vs the alternative: const styles = StyleSheet.create({
button: {
'&:hover': { backgroundColor: 'blue' }
}
})
The states here doesn't make a lot of sense, but I think it illustrates the idioms involved and how you end up focused on JS. This is so common I bet most devs who entered the market using React will see absolutely no issue in that.Another familiar case is not having direct control over a parent/child component's styles, only their state, making it impossible to do it with CSS. Not exposing `style` is very common in component libraries, and using CSS-in-JS means you can't easily target them with CSS selectors.
The fact that React is a plain view library and doesn't provide / interfere with the rest of your tooling is precisely the problem in my opinion, and does not exempt it from the resulting mess. The lack of standards has led to the proliferation of a thousand supporting libraries, all special in their own way, in turn making the definition of 'good practices' nearly impossible; it also gives way to flavour-of-the-month development practices, where popularity (and not necessarily quality/fit) determines what libraries most people use. Similar discussions can be had around SSR, accessibility, bundling, compiling, code splitting, animations, component APIs, state management, persistence, fetching data, and so on.
All they are are just fancy wrappers around putting more or less the same straight up CSS into the page. So you still use :hover or :active or whatever to do the appearance states in straight up css.
I still fail to see how React encourages adding event handlers to add hover appearances. A developer who thinks that's what to do with React was going to fuck that up with any technology.
const Header = styled('header')`
font-family: ${({ theme }) => theme.fonts.header};
color: ${({ theme }) => theme.colors.primary};
backgroundColor: ${({ theme }) => theme.colors.primaryBackground};
`
...where the theme object can be swapped out on the fly for different sections of a web app.I'd note out that this feature is also so edgy that the pushed argument shouldn't even occur that much.
It would be like "Oh hei, I need to dig up that super edgy star shaped hole using that shovel so I'm using it that way. Oh see, when I use it that way i'm inclined to do X. Therefore my shovel is encouraging me to do X."
I understand that frameworks might push you in a certain direction, but not this for React.
To set the context for the following statement, I've discovered that I prefer developing the nojs site. This mainly comes down to all the things that the browser does for me, but I have to handle manually in React, but it also includes something fun about figuring out the right css selectors to accomplish pseudo-interactivity without js. The point here is that I'm not personally inclined to avoid css.
And yet, when I work in react, I find myself writing less css, and the css I do write is closer to utility classes, something I never used in the nojs project.
I'm writing this on mobile but it's getting too long, posting and will move to desktop and edit in the reasons why I think React pushes me in the direction.
e: got here just as the edit window is closing, will reply to self instead.
This is also why I tend to think in terms of utility classes. When I'm writing JSX, I'm also visualizing how the final page will look (or actually looking at it, side-by-side). So, it's natural to be thinking about the actual styles I want to apply, not classes that hold several related styles. Sometimes I'm almost tempted to write inline styles, but thankfully the syntax is awkward enough to dissuade me.
The second reason has to do with how the html part of JSX is structured. When writing css for plain html, it's easy enough to see how the page is structured and go through it writing css classes for each block (or applying existing classes). Then you refactor as you notice common patterns and to put different style in the right places (oops, that margin should have been padding on the parent element…), like with any code. But with React, js is often changing bits and pieces of the dom itself, so it can be hard to look at and see the structure in the same way. Thus, it's easier just to apply the styles in the same place as everything else. (In React's defense here, I think if I were doing a similar amount of dom mutation using vanilla js, jquery, etc, it would be even harder to write css for it… but on the other hand, vanilla js doesn't encourage me to do nearly as much of it in the first place.)
I'm confused, are you saying you would prefer to disable the submit button without adding the `disabled` attribute?
For size of the bundle, just remember the node_modules black hole meme. The amount and size of JS libraries is no joke, it's wildly out of control. 2.5MB minified non-gzipped is common mostly because of a paradigm of "once you gzip it it will be small, and inflating that doesn't cost anything, and this way everything is preloaded!". Libraries come with a bunch of images embedded as Base64 encoded strings, the full localization tables, 40 1kb depedencies (left pad and friends), etc. etc. etc. These are all the default and no one changes defaults.
To make a reasonable web application today without all the insanity, you have to be very disciplined, because everything is pointing you toward doing dumb or crazy things.
The practice of removing unneeded code from a bundle using static analysis is commonly known as “tree-shaking”, but I like your version better. :D
I can see how easy it would be to accidentally get a bonkers js bundle if you start using external dependencies without monitoring how much code they ship.
Does React have a perf cost? Absolutely. But there's something else going on here.
Because when requirements change and your hover animation needs some additional flare to it in certain cases, you'll be glad that you had automated unit tests to verify original behavior still works along with your customizations.
"Wait," we told ourselves. "Surely, we can do some tree-shaking, replace momentjs, be strategic in our imports and shave a ton of that off"
With all of that we got it down to 1/2 of the size, but that was still too big for our needs.
javascript fatigue:
longing for a hypertext
already in hand
What are we doing? State management libraries? Hypermedia is the engine of application state. Send data to client as HTML and have the client apply styles over it, rather than converting from JSON to local objects and storing in some sort of reactive data store. You will find that semantically structured HTML is almost as economical as JSON.
IMHO this happened just because complexity and fads generate so much more money, in the long run.
Some people think hammer factory factories are elegant.... ;-)
That said, it’s a very simple and effective design. It’s an excellent program. But it’s not a fair comparison against other applications which, for one reason or another, need significantly more advanced state.
I mean, this website only loads a very small amount of text and has barely any user state besides a list of comments and posts. I would hope that it loads quickly.
The post mentions their HTML size decreased - most likely due to reduction in intermediate components and nesting.
Note that with an SPA you need to send templates (in the js bundle) + data (json api) to the client, which by definition will be at least as large as static HTML for the same content: HTML is nothing more than the template and content already baked in. In practice the JS templates are much larger due to containing the entire application logic + compiler overhead.
Finally, the benefit of having the templates already loaded is only realized over longer timespans, when probably half of your users are coming in with an empty cache anyway.
Mostly because of initial data. Index page is still on react, so you can go on https://kasta.ua/ and look for element `#initial`.
Not really by definition - tables rendered on the server side are a good example of a payload that can easily be larger than template + dataset.
Sending over generated pieces of html that update divs I find a quite nice compromise: not the complexity while having updates without refresh. Intercooler sounds like that.
I have integrated some very popular backends the past months and their portals are all SPAs and they all have this issue; hit refresh and you lost where you are, thrown back to login.
https://github.com/joelparkerhenderson/architecture_decision...
The simplest of them include "consequences" of architectural decision. For PWA these include the development of that kind of features.
Now to be absolutely honest. I prefer having a dedicated back-end that does one thing well and a front end that does one thing well. Even if I have to put in extra effort with few features just to have my source-code more dedicated and therefore cleaner to work with.
The thing is that PWA not only included the front-end dev, they also reduced the complexity of back-end. And that's a huge win I'd pay with these kind of features happily.
Stop crying around on HN and go dev your feature
Not reddit here, people like to talk about and ponder eachother's opinions.
Having argument alike "Oh I have to dev that feature therefor X sucks" is not a good enough opinion that i would like to read here neither.
Noone (well...) sits behind HN crying while doing nothing; but it is a platform where people go who actually make the changes or at least talk about them without dismissing them with ‘just use node/react and stfu’ or, almost the opposite, ‘just use wordpress and stfu’ like much of reddit and other programming forums (as far as there are).
It was a tremendous amount of busy work keeping metadata about DOM elements stored separately from the DOM elements, and hanging the values off the element was so much simpler in initial implementation, maintenance, and exploring other people's code.
Everyone was so excited about the virtual DOM in React 'n friends, whereas I saw both the functionality and the excitement as warning signs that I should stay away. I hoped this would turn out to be a fad, but it's a little long in the tooth for that scenario to play out now. For a while I watched news articles for the chinks in its armor, these days I'm more focused on other tools that satisfy niches, and wondering what will end up being the 'CSS3/ES6' moment for React where the browser does 20% of the work to have 80% feature parity with React.
React is not "bad for users". Developers build complex, fast apps with React all the time. It can be fast, but if you make mistakes with it then it's easy to make something very, very slow.
The app I work on is huge. It's ~8MB of uncompressed React + Redux in development (much smaller in production though), and pages include a lot of assets so they can weigh in at 23MB in the worst cases. A complex page can have up to 60,000 DOM nodes under React's control with thousands of event listeners. It starts in about 3s and never drops below 60fps.
Can one really make such affirmations regarding client rendered web apps? I'm assuming these numbers aren't solely measured on localhost in some state of the art development machine/device so won't it depend on the client's machine specs, browser, usage, bandwidth, etc?
It's better for the user if the UI assumes the request has been successful and updates the UI with a temporary success state, and then undoes the update if the request fails and gives the user the option to recover their update and try again. Most of the time there won't be a problem (especially with good client side validation) so they'll never see the recover state, and they'll never need to wait for a network request to finish either. Obviously you shouldn't use that sort of UX pattern for critical things though.
Give me a clean, server-side form submission any day over the "has it worked, hasn't it?" inconsistency of SPAs.
The virtual list make ctrl+f not working anymore, and I hate every single react page using it. Suddendly, on this webpage using virtual list, you ctrl+f something, dont find it, because the element does not exist.
A vue or angular manage your 60k elements list without any issue, you dont need to virtualize your list, and the search feature your your browser keep working.
And if your don't use a virtual list, react get performance issues starts when you get only a few hundreds of elements and you want to filter them.
Also, it start 'instantly' with other frameworks, not in 3 seconds, but below 500ms.
I can just bind ctrl-f to my search feature.
Also, it doesn't take 3 seconds to load but few ms as well.
See, you don't just pick a tech, you need to start from the specs and get what the user need.
Also, in pure HTML (because i tried it) ; the same rendering would be hanging anytime you try to act on something.
- On mobile, using menu to search in browser menus.
- When users use F3 to search, an alternative to ctrl+f.
You added a few bytes to reimplement a browser feature, and spend time on a feature that already exist, because of your tech choice. There is still probably some accessibility issues.
You can have easily 60k rows in HTML without any performance issue, you just need to pay attention...
"On mobile, using menu to search in browser menus" -> This is not a sentence.
I do add a "few bytes" to "reimplement" a "browser feature" ; but the reality is that i HAVE to implement search because it is hitting on 730000 per year records;
How is you ctr-f or f-1 feature is gonna search on 2190000 rows in 3 years ?
Again, you are too happy about your opinion that you spite it out like truth without even understanding specs.
Specs is what allow you to understand what's required, it makes no sense what so ever to talk about technology without understanding WHY you use it in the first place.
Is it meant for public ? employees ? How many rows do they deal with in their actual everyday workflow ?
You are pushing your workflow so much that you don't even consider about your users and that's another red flag for me.
PWAs have given so much in term of capabilities and mastery that I honestly wonder why I'm still talking about such things on HN while proper workflow about architectural design are ignored here.
" but the reality is that i HAVE to implement search because it is hitting on 730000 per year records;" -> True, there should be a search feature with a backend API.
"Again, you are too happy about your opinion that you spite it out like truth without even understanding specs."
Yes I want too far, your use case does require extra logic, because it's not good to send that much data to the user. I'm not pushing a workflow, im not a front end dev, but i do maintain frontend apps sometimes, i'm simply angry at React, because it cause pain to me as an user.
It's noticably slower (https://medium.com/dailyjs/a-realworld-comparison-of-front-e...).
The virtual list may be required for your use case, but as a user, I often met virtual list:
- Used for less than 100 elements
- ctrl f is not hooked on the 'webapp search feature'
- the 'webapp search feature' is noticably slower than the browser.
Also, here some reading, from a framework I don't use, about the virtual dom:
https://svelte.dev/blog/virtual-dom-is-pure-overhead
Now, not as an user, but as a software engineer, my soul cry when I see the architecture principle of such a framework fixed with a workaround.
I'm actually more of a preact fan and the community Jason Miller has created, their work have inspired me a lot in concern of front-end and javascript dev.
ctrl-f hook is effectively something that has to be considered when implementing such feature.
I'd argue that the list & search feature it self is hard, not as something to put on and program and get working, but as a user-experience and design perspective (I'd like to thank you about pointing that out by the way, I will definitely spend some time making sure it's there for my app)
The reason I can think of, is that we do actually take control over parts of the applications in a way that was not imagined when browsers implemented search function.
It almost feels like the "With big power comes big responsibility", but i don't like the word "power" in our case, so I'd change it to something alike to "With features that have extra consequences we need to have an equal amount of extra care to even considering them." as if it was hidden and we needed to understand the tool better to have it properly done.
I guess front-end dev is easy to get in and understand, but hard to master, and that could be why we end up with these rampant "half-done" apps that do not take those extra steps.
In the end, the rushed dev will probably just look to have it's app working and will not check these kind of "bugs" that have been caused by his decisions,
Tbh, without this discussion i'd probably have missed it too
That's pretty impressive, I've run into perf issues with far fewer actual DOM nodes than that!
idk if this is fair. OP was using some pretty niche tools (clojure) whereas best practice React metaframeworks like Nextjs may have addressed some of those pagespeed issues.
additionally, I highly doubt that the author has replicated this functionality by using his new turbolinky framework.
So the post is better titled "I improved webpage speed by throwing away React AND a bunch of UI requirements". which is fair dinkum, but less exciting.
Which functionality?
> a bunch of UI requirements
So your point is that you don't really know, but let's blame them for trying, or what?
Please answer their indirect question: "Did you replicate every of the react app's functionality in the app?"
I think GP's post is that _you_ don't really know the landscape which was why you reinvented the wheel, which I tend to agree with. You even agree with this unless you're being rhetorical here, no?
> Which functionality?
Let's take a look at every feature we see on the next.js page (https://nextjs.org/):
Zero Config Automatic compilation and bundling. Optimized for production from the start.
Hybrid: SSG and SSR Pre-render pages at build time (SSG) or request time (SSR) in a single project.
Incremental Static Generation Add and update statically pre-rendered pages incrementally after build time.
TypeScript Support Automatic TypeScript configuration and compilation.
Fast Refresh Fast, reliable live-editing experience, as proven at Facebook scale.
File-system Routing Every component in the pages directory becomes a route.
API Routes Optionally create API endpoints to provide backend functionality.
Built-in CSS Support Create component-level styles with CSS modules. Built-in Sass support.
Code-splitting and Bundling Optimized bundle splitting algorithm created by the Google Chrome team.
Now, do you want some or any of these things? How long do you think it will take to incorporate them into your new tool which you just rolled from scratch?
I guess at this point I'll add in some opinionated views here. At a certain point along your software engineer journey towards becoming a senior engineer, you are supposed to understand that undifferentiated heavy lifting and implementation is a bad strategic move in terms of technical strategy. If I am your CTO and you are telling me that you want to write your own Intercooler-esque library and move all of our core frontend checkout code away from React (an ecosystem with conventions that much of the rest of the world uses) and towards a proprietary solution I am going to ask you for a good reason. That is to say, I am unlikely to be persuaded by "I didn't spend enough time deeply researching how the rest of the ecosystem's users handle these issues" and I am likely to gently remind you that we will likely get more mileage out of investments that make our user experience better rather than scratching the itch to write a new framework.
> How long do you think it will take to incorporate them into your new tool which you just rolled from scratch?
Here is the news: we will never add them to the new tool. No TypeScript, no compilation, no routes, nothing.
> If I am your CTO
Good news you're not, right?
I think that's part of the issue. You have built something outside of an ecosystem. Have you planned for what will happen after you leave? Have you been on the receiving end of inheriting a codebase written in a language (like ClojureScript) that was buzzy for a while but then never took off? It happened to a lot of people with Coffeescript.
> Good news you're not, right?
Are you sure that's good news? Because what I see here is a poor choice of a niche language (ClojureScript) which lacks traction and will probably die long term. Moreover, because it lacks an ecosystem (or more accurately, that ecosystem is not the exact flavor you want), you've taken liberties to write things completely from scratch. Why not use Next.JS? Why not use Rails + Turbolinks? Why not reconsider writing crucial infrastructure from scratch when it already exists in many forms? Most damningly, why should you be trusted to reinvent the wheel if you lack the patience or thoroughness to go through previous solutions to this problem and put together a convincing argument for why they fall short and you need to make something new?
These technical decisions around infrastructure, stack and ecosystem are ticking time-bombs. They are almost certainly a long term technical risk and an eventual roadblock to recruitment/onboarding. I think it's unfortunate that you have wasted your time reinventing problems that have already been solved instead of focusing your talents onto areas which deliver more value to your customer. As you are working on e-commerce, this could be anything from marketing and demand acquisition to checkout funnel conversion to fulfillment, up-selling and cross-selling.
If your organization's leadership incentivized engineers to seek these kinds of investments, it would probably result in you choosing a stable stack (which, while imperfect, is good enough, has a larger ecosystem of maintainers than just the company, and so has less of a risk of blowing up in a few years) so that you could focus on investing into more customer-centric engineering. It's a shame because I think that this kind of engineering is the kind that helps engineers grow and mature in seniority. It gives them the capability to become technical and people leaders, who are exactly the kind that most companies that employ leaders need to have.
But that can never happen when engineers don't develop the judgment to determine which problems are strategically valuable to the business and which ones amount merely to overhead. And of course, many companies see no need to invest in or to empower their engineers this way, so this kind of thing keeps on happening because you need to work on something stimulating or what would be the point of work? Feel free to disagree, but based on what I've seen, I think you are working on the latter. I guess all I could ask you is imagine what kind of amazing results you and the company would see if you focused all that incredible energy you put into this infrastructure into delivering customer value!
But it does illustrate how React isn't a magical solution to the front-end woes and how complicated the whole thing still is to do right.
I'd still use React for projects, but for now I've been incredibly happy with the LiveView solution that Phoenix/Elixir offers (or the variants for other frameworks. Blazor for C#, LightWire for Laravel/PHP?).
It's surprising how often I'll work on something and realize that the solution is quite simple now, where before it would definitely mean some serious thinking.
For example: libraries. I remember so many projects where I needed do do some date formatting or manipulation. Moment.js was the obvious solution, but including the whole library was not an option.
With LiveView I can just pull in whatever dependency I want, because it's all server-side. It's only the markup diff for the specific component that gets sent down the wire.
Or security. I need to show a user, but only a 'friend' can see the email address (or other profile details). The 'old-fashioned' way would involve separate API calls and a certain nervousness that perhaps I might end up in a situation where the front-end behaves how I expect, but the API calls somehow expose non-friend data.
With LiveView I can just add a conditional statement to the view, and since the resulting HTML is all that does to the client, I'm done!
Of course this only works with a persistent and relatively low-latency connection, but I can't remember the last time I worked on a project where this wasn't an implicit assumption.
I'm perfectly happy using React/Next/Vue when necessary, but it's a really strange experience to read these kinds of articles and threads these days when for so much of my day to day these problems just went away.
I’m also exceptionally confused why the Pagespeed score was sitting at just 5/100 - it doesn’t sound like the dev team actually understood the result and attempted to resolve it.
It sounds like the author has found some new technology they’re happy with for now, but it sounds like all the previous problem were self inflicted and they’re bound to repeat them again.
While different tech and frameworks has an influence in the problems you’ll face, you’ve still got to do good programming.
This can be remedied by using CSS or styled-components.
I'm not saying that's how it should be done. I'm just clarifying what the author of the article was referring to.
The entire documentation block for that is prefixed with a big yellow-box warning:
> using the style attribute as the primary means of styling elements is generally not recommended.
And then it links to https://reactjs.org/docs/faq-styling.html which just says over and over again "use class names"
All that I’m saying is that, as opposed to some other opinionated frameworks, react let’s you do pretty much whatever you want, which is great for speed development but can also exhausting in the huge amount of decisions that need to be made.
"Nothing is more permanent than a temporary solution"
But, after having witnessed, and having committed, countless acts of perfecting something until it died on the vine, I would consider, "This hack is hard to change because so very many people are paying us money in return for the privilege of relying on it," to be a very nice problem to have.
That doesn't seem to be the position that's being advanced here. TFA, for example, starts out talking all about the author fell in love with React for its easy maintainability, before moving on to the need to make some tweaks for the sake of user experience, and finally ending by proposing a design that is based on a fairly principled set of design tradeoffs.
And the parent commenter, at least to my reading, isn't saying, "phooey, who cares about maintainability," they're saying that, while they don't like React, they do have to acknowledge that there is pragmatic value in it not being so rigid that you can't just grind out the code when business realities mean that that's what you need to do.
Long story short, if what you're trying to advocate is a flexible, middle-path-type approach, I don't know that this is the best place to go searching for a debate on the subject.
I am not opposed to React for like, a calendar application, or a particularly complex part of a web app, but most web apps have 90% CRUD and 10% shiny.
And with well-tuned SQL and turbolinks dropped on, Rails pages load in 30-60ms with no page refresh.
In my particular case thought I've been opting for Golang given that my web app needs to perform a little more that CRUD. And in regards to the CRUD part I've been heavily relying on PostgreSQL functions, thus instead the pain of a ORM I just have simple raw sql `SELECT * FROM api.get_user_data(?,?);`
I'm not saying that is not possible to to things like this on Ruby, but when your application is a little more than CRUD RoR starts getting on my way...
I also heavily rely on Postgres views, which ActiveRecord just sees as read-only tables, so my Rails code can still call `user.api_data_entries` without any ORM wrangling.
Rails devs who’ve mastered a lightweight js framework like Stimulus and perhaps a webhook utility like ActionCable are immensely more productive than a team of very separate front and back end devs.
Basecamp take this a level further whereby each dev is quite heavily involved in the design process, and their designers can also code in Rails.
With Hey I think they’ve shown that it can not only be lightning fast but pretty shiny!
Especially in the past few years, as browsers have implemented a lot of animations and scaling in CSS which offloads to the GPU. You don’t want JavaScript/CPU doing that math anymore.
Component-based JavaScript frameworks “force” us to organize our CSS in the same way outlawing cars in favor of bikes bikes ensures everyone follows the speed limit.
Ok, so I haven't gotten around to learning React yet, but I understand it to be the next iteration of what Angular, which I have learned, was trying to be. Angular "let you do whatever you wanted", too, which made me wonder why it was even there in the first place. Javascript lets me do whatever I want, I just have to write a lot of code to do that. In theory, a framework ought to reduce the amount of code I had to write, but I found that I was actually writing more code to work around the 90% of things Angular didn't do than I would if I just used Javascript and DOM manipulation. Frameworks that "let you do whatever you want" usually end up being the thing they're supposed to replace with extra steps.
JSX comes down to being a convenient way to write HTML in your JS instead of JS in your HTML. After that, it’s just vanilla js.
So, the problems here may have had more to do with the clojurescript stack (which I am not much familiar with), or author's lack of familiarity with javascript optimization strategies than react, SPA model or client side rendering.
However, CLJS really does feel like application development (which is why I like it, tbh) and the community doesn't seem to pay much attention to the use-case of regular web pages which just need some JS components to add interactivity. Googling for strategies to optimise CLJS for that use-case won't get you many results - you have to understand the stack well enough to do it yourself.
It seems everyone uses <body><div id="app-root"></div></body> but React is perfectly happy being scattered around the page.
It's just a thought, I haven't tried it myself yet - has anyone else?
I and some other built while i was at Poetic in Houston, Tx. https://www.houstonfoodbank.org/find-help/agency-locator/
New features were still desired so we built/repurposed react/redux components into what we called “hybrid” pages. It worked great for us!
For instance, you could build an e-commerce shop as an SPA, or you could target specific parts that process user interaction dynamically / fluidly - such as the checkout process, adding to a cart,... - and consider those as separate applications.
There are also trade offs. Search and navigation, for instance. You could build an SPA for an entire search engine. But then you may end up doing heavy lifting, like dynamically managing URL state through routing components, which is something browsers already do themselves: the only gain being that you don't reload the entire page.
So, the big question boils down to: what are you really trying to solve? A UI/UX problem? A performance problem? A maintenance problem? Something else? And who are the stakeholders, who's using the stuff you're gonna build? What are their intentions and motives?
That's when you come, to a conclusion: there's no silver bullet. The architectural design you choose needs to be an informed choice above anything else. And it should be informed by your specific context rather then the affordances provided by the tools at your disposal.
The hard part is sitting down and taking a bit of time up front to think and articulate an argument that, given your context, validates choosing a particular strategy. (Personally, I tend to sit back and stare at the ceiling with my notebook and a pencil, but that's just me.)
We have put together a small collection of fairly generic react apps that mean we can put one on a page, put in some config and have it displaying a report generated in SQL in about as long as it takes to write the SQL for the report. We have used this approach for generic SQL reports, SharePoint lists, imgage retrival and entry forms. Having the library of options to hand has meant we can confidently assemble a new (fairly complex) page much quicker than previously - and be confident that it will work as it is reusing known good components.
Then I realized Javascript could do lexical closures which meant the client could keep track of the targets, which also meant the server no longer had to care about things servers shouldn't care about.
The next realization was that DIV IDs are global variables and thus in most cases a bad idea, so now my event handlers automatically search upward (and sometimes sibling-wise) from 'this' for DIVs matching classes or other selectors, to keep the scope local.
This TwinSpark library seems like the next iteration of all the good ideas, plus even more flexibility and proper separation of concerns, without JQuery or other dependencies.
Bravo!
In the past I have used Angular and React - these days I just always reach for Svelte (speed and simplicity).
Smaller bundles, faster, easier to use ... everything one can ask for
I would also recommend to anyone to read his blogs about different approaches to client side rendering, and the technology behind Solid. It is a really good read regardless of the choice of using the library.
All joking aside, I would argue the client side vs server side is a false dichotomy. The web has been doing a hybrid of both for a very long time now. Each have their pros and cons and there hasn’t been anything stopping engineers from using a mix of both, where it makes sense.
Now about those cargo cult marketers...
Whenever I read this, I usually take it the author is being serious. However, how long does it actually take to load a 88kb library these days, is it really 'monstrous'? If this was the authors top performance drain based on profiling, I commend their technical abilities.
And a "monster" is sarcasm referring to that React bundle I described before.
1) I wasn't code splitting by page, and had a couple heavy dependencies (which made things worse)
2) I wasn't pre-rendering my create-react app via react-snap. Meaning during the CI build react-snap runs Puppeteer visits each page on the site, and generates ready-to-go html versions of each page.
Those two changes took me from a 7/100 to a 95+/100 in short order. Makes logical sense too. Now a days the site hovers at 85/100. But I don't have the time right now to reinvestigate it.
With the options at the time, I'm happy with my tech choices. If I had to start with React again today. I would do Next.JS with a static build output. Would save me a bunch of time scaffolding things.
pjax would be a better OG similarity: https://github.com/defunkt/jquery-pjax
"We need to look at it from two sides: if it’s good for developers and if it’s good for users."
It is a pity this change in thinking required the pressure from Google Pare Rank, but now I see it as something very positive.
Always remember: code is written once, and executed thousands or even millions of times.
No optimization is worse than "premature optimization", and you probably misunderstand what "premature optimization" means anyway.
And then it hit me. MBA is not the slowest laptop out there. It is much worse for a large part of our users.
This is where I started thinking we should jump off the hype ship. :-)
About complex logic, it is everywhere. I once worked at an big ecommerce company and the server-side catalog page was more then 2000 lines, nobody want to touch that page. But it would be easier with React since we can break it down to smaller components.
Your 2.5MB minified bundle is actually too big.
Because it's modern? In all seriousness I've often asked questions along these lines and haven't always received great answers.
1. https://alarisprime.blog/e-commerce-case-study-building-fast...
2. https://alarisprime.blog/e-commerce-case-study-building-fast...
3. https://alarisprime.blog/e-commerce-case-study-building-fast...
* Code splitting * Loading of the code (at appropriate times, eg: ) * Any other optimisations
I think the author simply failed to do this well and then blamed the library for their own shortcomings, and moved on to the 'next shiny thing'.
There are plenty of patterns you can use to make your React app responsive, and many tools to help you achieve that, it's just a matter of being able to implement those tools effectively.
I wonder why the author did not contribute to intercooler rather than writing his own version. Would it really have been that difficult to avoid inheritance (or add an inheritance free api) and add batching to that library?
1) htmx started later than I did
2) inheritance is like a plague, and I'd really want it to not exist
I'll try to explain my stance. When you're a developer, you naturally drift to solutions which require you to write less or write faster. And inheritance certainly helps with that in simple cases. TwinSpark had inheritance up until we tried to implement sign-up/in logic.
Damned popups... Anyway, that's the day we've killed inheritance: https://github.com/kasta-ua/twinspark-js/commit/5714ceea9836...
And if you have two APIs - with and without inheritance - developers will use the first one by default. And when it bites you it'll be painful.
So if Carson reads my rant and decides to remove inheritance - I'll gladly move to htmx. If not - maintaining a library which is less than a thousand lines of code is not that big of a burden. :)
Nothing better than a nice pop-up to ruin your day... they're a different kind of plague
Actually the original author of Intercooler has a renamed 2.0 version that removes some warts - including the jQuery dependency: https://htmx.org/
No framework solves the problems of knowing your tools and learning every day, React is no different, not a red pill for every problem, you have to know it's quirks the same way just any other language/framework/tool you use.
Plain javascript is painful.
It’s nit necessary to throw out react to address the issues identified here.
The author comes across as fairly junior.
Which is exactly why he isn't advocating plain javascript. You should take a look at micro-frameworks like Intercooler (and htmx, unpoly alpinejs etc). For devs who don't remember the days before megaframeworks it can be quite illuminating to see a different way of looking at things.
Overall not a good critique of React as such to justify the "throwing away React" title in the front page of HN. In fact, not a lot of good conclusions can be drawn from the read. Maybe just "if YOU build/find YOUR own framework for YOUR problem space excitement will follow."
On the other hand, I doubt the complexity issues, also mentioned by the OP throughout the article, was solved by using the new framework. In fact:
> On the developer side, I think React is better still
So tit-for-tat.