In the Famous
End Game, Avengers assembled to fight the threat and they won. This is the
End Article for a
Split Second Later series, and it's time to assemble all our heroes.
Before we start - let's recap the previous series
☠️ Who is the BAD GUY ? - the
Time between you hit "enter", and your site or application is "ready". And it does not matter what does mean "ready" for you - for your user it's always just "ready". So simple, it's really so simple.
🔥 Who are the GOOD GUYS? There are many!
- a faster Server-Side or CDN response
- a faster Client-Side boot
- a smaller Network payload
- fewer roundtrips for resources and fewer blocks
- right content and actions delivered in the right time and the right order
Let's found how they would make your site, or application, be ready just a split second later.
👉 In an alternative universe (multiverse?!)
Das Surmahas written the same story - techniques to make a web app load fast, even on a feature phone. Check it out
There are a few ways you can display a
final picture to your customer. To be more concrete - two ways. As HTML-first, and as JS-first. But this is not just two ways - they are creating some spectrum, and let me cite the famous Rendering on the Web to explain it:
However, SSR at this comparison table has a con - slow TTFB, which means - you will start getting a response from a server not as soon as in other cases.
This limitation is driven by two technologies:
- MVC, which is a common way to SSR react applications - first get everything, then read everything, then send everything
- lambda functions of any sort. Which by design accumulates everything you want to send, and then "return" it as one big string.
While lambdas are not yet stream rendering compatible, and there is nothing you can do with it, "MVC problem" is a lie - nothing stops you from sending
<head><script src='main.bundle.js'> first, letting user start downloading js-bundle, then read all data, and then
renderToStream the result, significantly reducing TTFB. Just get rid of declarative helmets, which are not single rendering pass compatible.
Yes, to be honest - to achieve the best results, you have to get rid of
react-helmet. Patterns they implement are not SSR friendly.
This technique is known as progressive rendering and here is my friend @flexdinesh explaining it in details:
Btw, do you still remember the second article of this series - React Cache?
So you open the page, server sent some bytes - the rest is browser job.
- download all needed scripts
- download all needed styles
- download all needed data
- display something to the client, and ideally from the
Preloading the right content is key here. Preload font's before they got used by HTML (which is not loaded yet), and CSS (which is not loaded yet), as well scripts.
The majority thinks that this is achievable only thought
HTML LINK meta tag, thus not usefull for lamdas, not yet compatible with stream rendering, but the truth is - you might send
preload as a HTTP, not HTML header, you can send from a service "before" labmda.
Link: <https://example.com/app/script.js>; rel=preload; as=script // <link rel="preload" href="//example.com/widget.html" as="document">
- display something to the client, and ideally from the
And that's the key point - displaying something "once" is a key. I am not talking about the Death By A Thousand Loading Spinners, so popular among modern SPA - even Progressive JPEG(considered as "good" for slow connections) is leading to multiple renders(while a picture is progressivle loading) wasting CPU(and battery) of your phone. So doing something "once" - is a key for a more idle CPU, and more power to do other stuff.
Finding the good balance between network and CPU utilization, as well as between render/redraw/layout - is a key to better user experience.
Finding the good balance between data sent from a server (the less you send - the faster you read it), and data requested by a client (why not to fetch something a bit later? Why not... not?) - is the point of equilibrium.
...and don't forget about critical CSS.
It's always about balance
Is about making your scripts smaller, and about using as fever lines of code as possible. It's about code splitting and code optimization.
- properly isolate your use cases and your code from each other
- use code splitting
- measure intermediate and the final results. size-limit and import-cost are your best friends.
- try deferential bundling to ship more efficient code
- CSS usually is not a problem
Optimizing JS deliveryis an article you have to recap.
HTTP nowadays is a very complex thing. It's not only about fetching the data from the remote server, but also about TSL handshaking secure connection, connection latency, and effective CDNs.
The key to a faster (up to 2x) response is to use as fewer "connections" as possible, and trying to fit your content into
TCP window size blocks, to optimize the transport layer (14kb according to Yandex research).
Fun fact - according to the statistics acquired by Yandex(link in Russian)[https://habr.com/ru/company/yandex/blog/358944/] - the actual "downloading" part is NOT a problem for mobile phones - but DNS lookups, and network ceremonies are.
Is about loading something when you need it. It's also about coherence, and loading that something when you actually need it. It's also not about loading, but executing.
It has many names, like:
- critical CSS, styles for a
footerdefined before the
footer, not the
header- are styles delivered at the right time
- some data stored during SSR in HTML
data-attributes, not in a single and global Redux store - is data defined in the right time
- js code executed, and HTML rehydrated when it really needed, not in the real beginning (also known as a partial hydration) - is the right action, done in the right time.
- react-imported-component for code splitting
- webpack-imported for a better bundler integration
- devolution for diferential bundling
- used-styles for critical style extraction.
- react-prerendered-componet for partial hydration and SSR fragment caching
And so, it's time to explain why you should start with