Loading chunks on demand - beyond the router (part 1)
Tags: performance, frontend
Published: 2023-08-11 00:04:18

It's time to control when your application requests the chunks of your page and optimize the loading.

Let's look at how to split up the chunks and load them at the right time. I'll show it with a [personal project](https://frontend-pattern.vercel.app). The stack is as follows: 

- [React](https://react.dev/) (SPA);
- [Vite](https://vitejs.dev/);

The same is applicable (**changing the syntax, obviously**) to any other JS frameworks and bundler tool, consult the doc to know how.

NOTE: This post is split into two parts. [Read part 2 here](https://dev.to/tassiofront/loading-chunks-on-demand-beyond-the-router-part-2-4349)

## What are chunks at development word?

Usually, front-end developers have contact with .ts, .vue, and .tsx files, but browsers don't understand them. To do so, it needs to convert those files into .js files - and they can even be optimized, typically by using a build command. 

Even though all development files can be converted into a single .js file, it's not recommended because of the performance impact. Ideally, those files a converted into multiple .js files (chunks) to take the ability to load the files at the moment they are required - thinking on user navigation.

So, chunks are .js files that, together, define a whole front-end system, in a nutshell. 


## React.lazy

[React.lazy](https://react.dev/reference/react/lazy#lazy) is a React tool to load js code on demand, optimizing application performance. The idea is to avoid downloading, parsing, and compiling js code before it's required. Ideally, the main mindset it's to define the load order so your application looks faster.

It's usually used for lazy loading routes on SPA applications, but I'm gonna show you how to use it in other scenarios such as using data from an API.


## Current project bundle

To start, let's see what the project looks like:


![articles page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l63ys2d9bu3vxtx5f2zv.gif)


It's a simple view that gets my Dev.to articles and renders a card for each item from the API (https://dev.to/api/articles?username=tassiofront).
Now, let's see what the load page looks like in the Network tab:


![before load page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r3254wscolmpegf1ef0g.png)


It's possible to see that the article HTTP request is called after **all** JS files are downloaded, parsed, and compiled. But, does it really need all that JS content before calling the API? Well, it just needs the card's chunk when there is data from the API, right? So, Why not load it after the GET has finished?

Note: I have reduced the whole code to teaching purposes, but at the bottom, you can find the commit and the full source code. Read the comments to understand.

```TS
// READ: importing lazy and Suspense APIs
import { useEffect, useState, Suspense, lazy } from 'react';

import BaseScreen from '@/components/BaseScreen/BaseScreen';
import Section from '@/components/Section/Section';
import { texts } from './enums';
import { getOwnerDevArticlesByUserName } from '@/services/devPublicApi.service';
import { IArticle } from '@/models/Article';
import RouterFallback from '@/components/RouterFallback/RouterFallback';

// READ: Creating a function to load the ArticlesContent component later. This is the component that renders all card articles
const ArticlesContent = lazy(
  async () => await import('./components/Content/Content')
);

const Article = (): JSX.Element => {
  const [articles, setArticles] = useState<IArticle[]>([]);
  const getUserInfo = async (): Promise<void> => {
    const response = await getOwnerDevArticlesByUserName();
    setArticles(response.data);
  };
  useEffect(() => {
    void getUserInfo();
  }, []);

  return (
    <BaseScreen heading={texts.heading} description={texts.description}>
      <Section>
        <>
          {articles?.length > 0 && (
            //READ: Avoid downloading, parsing, and compiling the card chunk before it's required
            <Suspense fallback={<RouterFallback />}>
              <ArticlesContent articles={articles} error="something went wrong" />
            </Suspense>
          )}
        </>
      </Section>
    </BaseScreen>
  );
};

export default Article;
```

With that simple changes, let's see the difference in the Network tab:


![after load page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l0w552hon5520aaxqscf.png)

Do you see? 

Now there is one more chunk (Content.hash.js) which is loaded after articles GET. Wait, one more chunk?! Isn't it bad? NO!

There is no more code now than before, but now we split up our code removing what is not required before it gets all article data, creating a logic order, and optimizing the load page.


## Conclusion

In this article, you saw a bit more about chunks, and how to split them using React.lazy. Creating a logic order and optimizing the load page.

This is something interesting to keep in mind when creating new stuff. It's not just creating, but how it's created also matters.

- [Source Code here](https://github.com/tassioFront/frontend-pattern)
- [The commit with those changes](https://github.com/tassioFront/frontend-pattern/commit/d2c40d82f4d8d40d431755e25bb0fa4c847cf496)

[See my other articles](https://frontend-pattern.vercel.app/articles)

## What's next
[Read part 2 here](https://dev.to/tassiofront/loading-chunks-on-demand-beyond-the-router-part-2-4349)