Website Performance in 2021: React Server Components, Next.js Static Generation, and Linaria Zero Runtime CSS

As the clock ticks closer to May, the month Google committed to rollout a new search algorithm update based on performance and page experience, contributors of popular open-source projects have joined the movement. In this post I highlight a few current and upcoming features / libraries we can utilize to boost website performance in our React websites.

This post is brought to you by Foo who provides Lighthouse and Web Vitals monitoring services. Register for free or choose a premium plan to automate web page performance and page experience testing.

Static Generation and Build Time Data Fetching with Next.js

Next.js is a framework for React that enhances developer experience by abstracting configuration, standardizing best practice as defined by the community, specifically simplifying the setup for "Server Side Rendering" (SSR). At the heart of this framework is a method called getServerSideProps which provides a means of returning server side data on initial component mount at run time.

As of Next.js version 9, we can now fetch data at build time! To understand the performance impact, let's think of an example in which a web page depends on the result of a few HTTP requests from an API. In our example endpoint "a" depends on endpoint "b" which depends on endpoint "c", so we can't dispatch these requests concurrently. This data fetching would suspend and prevent page load for a variable amount of time depending on response of our API. Behold getStaticProps to the rescue! getStaticProps is similar to getServerSideProps except it returns data at build time and generates output in static build files. There are many cases unsuitable for this method, but if you're fetching data without variability, like from a CMS - getStaticProps might be a great option for you.

Performance Impact

With getStaticProps we can improve web page performance by eliminating run time data fetching to reduce Time to First Byte (TTFB).

Zero Runtime CSS with Linaria

CSS has long been a dreaded subject in React development for some, and nowadays is more complex than ever. Linaria is a flexible CSS in JS library that can accommodate a wide range of familiar syntax and techniques. It supports syntaxes similar to both Styled Components and CSS modules. One key feature of this library is its zero impact on JS bundles as CSS is extracted at build time. Below are advantages of Linaria over other CSS-in-JS solutions from its documentation.

  • CSS is downloaded and parsed separately from JS
  • No extra parsing needed for CSS
  • No style duplication on SSR
  • Catch errors early due to build-time evaluation
  • Familiar CSS syntax
  • Works without JavaScript

Performance Impact

These advantages can improve performance metrics including Speed Index, Time to Interactive (TTI), and Total Blocking Time (TBT).

Zero Bundle Size React Server Components

Are you noticing a pattern yet? Zero is a good number in terms of performance, especially in regards to bundle size. Server Side Rendering (SSR) is not a new concept to React. SSR has been feasible since the early days and greatly improved with the introduction of ReactDomServer a few years ago.

As the demand for SSR standardization has increased, the React team has joined the performance movement by proposing a solution for server components. At the time of this writing React Server Components is still in research and development. Below is a summarized proposal from the RFC.

Server Components allow developers to build apps that span the server and client, combining the rich interactivity of client-side apps with the improved performance of traditional server rendering:
  • Server Components run only on the server and have zero impact on bundle-size. Their code is never downloaded to clients, helping to reduce bundle sizes and improve startup time.
  • Server Components can access server-side data sources, such as databases, files systems, or (micro)services.
  • Server Components seamlessly integrate with Client Components — ie traditional React components. Server Components can load data on the server and pass it as props to Client Components, allowing the client to handle rendering the interactive parts of a page.
  • Server Components can dynamically choose which Client Components to render, allowing clients to download just the minimal amount of code necessary to render a page.
  • Server Components preserve client state when reloaded. This means that client state, focus, and even ongoing animations aren’t disrupted or reset when a Server Component tree is refetched.
  • Server Components are rendered progressively and incrementally stream rendered units of the UI to the client. Combined with Suspense, this allows developers to craft intentional loading states and quickly show important content while waiting for the remainder of a page to load.
  • Developers can also share code between the server and client, allowing a single component to be used to render a static version of some content on the server on one route and an editable version of that content on the client in a different route.

Performance Impact

Adoption of React Server Components will reduce bundle size which is one of the main factors of many performance metrics including Speed Index, Time to First Byte (TTFB), Time to Interactive (TTI), and Total Blocking Time (TBT).