A simple change improved Chakra UI's PageSpeed significantly
Tags: performance, nextjs, chakraui
Published: 2021-12-18 18:57:50

> Originally posted at [nikolovlazar.com/blog/improving-chakra-ui-page-speed](https://nikolovlazar.com/blog/improving-chakra-ui-page-speed)

I've noticed that the PageSpeed scores for [https://chakra-ui.com](https://chakra-ui.com) were not that great. I know that
we've built the page using the best practices, but for some reason the scores weren't what we expected. I took some time
to analyze the metrics and noticed that the TTI (Time to Interactive) and TBT (Total Blocking Time) were crazy high!

![Chakra UI's Old PageSpeed Metrics](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p4r4u7dw32lpey97n1on.png)

Scrolling down in the Diagnostics section I noticed the "Avoid enormous network payloads" issue, notifying me that the total
size of the network payload was 7,053 KiB, and that's way too much! Clicking on the issue revealed that 9 out of 10 requests
are from CodeSandbox, because of the CodeSandbox embed that was on the page.

![The enormous network payloads list](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9c84x3ekaxk5z8i5p5nq.png)

Then I remembered that CodeSandbox released their [Sandpack](https://sandpack.codesandbox.io/) component toolkit that you
can use to create live code editing blocks. Since that's an npm package that you install, I figured it will definitely be
more performant because its code will be compiled, optimized and shipped along with the page. So I decided to swap out
the old embedded `iframe` with the new Sandpack component. And the results were surprizing:

![Improved PageSpeed Metrics](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c7vhv6pcx5cz3y6t6yr9.png)

All of the metrics have been improved significantly:

- CLS: `0.029` -> `0` 🚀
- FCP: `0.6s` -> `0.4s` 🚀
- LCP: `0.6s` -> `0.5s` 🚀
- SI: `1.7s` -> `0.6s` 🚀🚀
- TTI: `9.8s` -> `1.6s` 🚀🚀🚀
- TBR: `4.9s` -> `0.3s` 🚀🚀🚀
- Overall Score: `58` -> `86` 🚀🚀🚀

Let's walk through the changes. First, I installed the Sandpack package:

```shell
yarn add @codesandbox/sandpack-react
```

Then I created a simple and generic component that displays the `Snowpack` component, but allows the data to be provided
from the outside:

```typescript
// src/components/sandpack-embed/index.tsx

import { Box, BoxProps } from '@chakra-ui/react';
import { Sandpack, SandpackProps } from '@codesandbox/sandpack-react';
import '@codesandbox/sandpack-react/dist/index.css';

const SandpackEmbed = (props: BoxProps & SandpackProps) => {
  return (
    <Box
      as={Sandpack}
      {...props}
      options={{
        ...props.options,
        showLineNumbers: true,
      }}
      theme='dark'
      template='react-ts'
      customSetup={{
        dependencies: {
          react: '17.0.2',
          'react-dom': '17.0.2',
          'react-scripts': '4.0.0',
          'react-icons': '3.11.0',
          '@chakra-ui/react': '1.7.3',
          '@chakra-ui/icons': '^1.1.1',
          '@emotion/react': '^11.7.0',
          '@emotion/styled': '^11.6.0',
          'framer-motion': '^4.1.17',
        },
      }}
    />
  );
};

export default SandpackEmbed;
```

It's basically a `Box` component, rendered as a `Snowpack` component, but its props are the `BoxProps` merged with `SandpackProps`.
That way we can pass Chakra style props, and Sandpack configuration props and reuse this component everywhere.

Then I simply replaced the `iframe` on the homepage with the new `SandpackEmbed` component:

```typescript
<SandpackEmbed
  options={{
    editorHeight: 600,
    editorWidthPercentage: 60,
  }}
  files={{
    '/src/App.tsx': App,
    '/src/index.tsx': Index,
  }}
  zIndex={0}
  tabIndex={-1}
/>
```

The `App` and `Index` variables that you see on line 7 and 8 are simple strings. It's the code content that we want to have
inside of each file specifically:

```typescript
export const Index = `import * as React from "react";
import { render } from "react-dom";
import { ChakraProvider } from "@chakra-ui/react";
import App from "./App";
const rootElement = document.getElementById("root");
render(
  <ChakraProvider>
    <App />
  </ChakraProvider>,
  rootElement
);`;
```

And that was it! A simple change drastically improved the page speed, and also opened up possibilities to reuse the
`SandpackEmbed` component throughout the whole website. I plan on swapping the [react-live](https://www.npmjs.com/package/react-live)
package with the `SandpackEmbed` as well. I'm not sure about performance boost, but a bonus feature will be the ability
to create a CodeSandbox sandbox directly from the website.

Here's the PR if you're interested to see all of the details about it:
[![Pull Request](https://opengraph.githubassets.com/f4a95bd3aa5113a1f599f5a810edeb16b885f3364b0443dc3c34a02c3290a5d8/chakra-ui/chakra-ui-docs/pull/154)](https://github.com/chakra-ui/chakra-ui-docs/pull/154)