5/15/21

React Static Web Apps Manage ChunkLoadErrors on Dynamic Routes

The React JavaScript framework for Single Page Applications (SPA), which can be hosted on Azure Static Web Apps (SWA) or CDN hosting, supports the concept of Code Splitting by loading pages/routes dynamically instead of building one single package.  The benefit of Code Splitting is that it enables for faster load time on the user’s browser as opposed to loading the entire application on one single request. This feature however also introduces other concerns that we need to manage with code otherwise, the user can end up with a white page in front of them as the application is unable to render the requested content.

ozkary chunk load error


To leverage Code Splitting, we load the page routes by using React Lazy* Loading and Dynamic Import features. This way the page, or chunk, for the selected route is loaded only when it is requested. Because this is done a run-time, a new request is made to the server to download the chunk of code that is needed to render the page. Yes, this is a server-side trip to get the additional resources, and the application still works as an SPA.

Note:  Lazy loading is an application architecture that is used to load code in memory or web pages only when it is needed. This improves application performance and load time.

Because a server-side request must be made to download an additional chuck of code and render the route or page properly, there could be failures that are reflected as the following errors:


Uncaught ChunkLoadError: Loading chunk 2 failed.(timeout)


The failure could be due to two main reasons:

  •         There is a network latency issue and the content failed to download
  •          The client application may have been cached on the browser and App update has replaced those files with new hash codes

For the network problem, we can add some error handling and retry logic to allow the application to get the chunk again. We do need to be careful here and avoid locking the user on some retry logic because the second case, app update, can be happening, in which case the only way to solve the issue is by refreshing the entire app again.  Let’s look at the code below and talk about the root cause of this issue.

 

Ozkary - React Dynamic Routes

After looking at the code, we can see that we are lazy loading dynamic imports by using promises.  Those directives tell the compiler to create a chunk for that route, and when that route is dynamically requested by the user, the chunk is downloaded to the browser. The issue with this code is that there is no error handling, and promises can fail to download the chunk resulting on the ChunkLoadError.

To address this issue, we create a loader component that can manage both the error and attempts to download the requested chunk. At the same time, this component needs to be able to limit the number of retries, to avoid an infinite loop, and decide to load the entire app again. Let’s look at a simple implementation on how that could be done.

Loader Component


ozkary route loader component


Using the Loader Component 

 

ozkary load routes with error handling


After looking at our solution, we can see that we are lazy loading the loader component which manages the promises, errors and retry activities. The component uses a default limit for the number of attempts that should try to download the next route. This is done by calling the same function recursively and decreasing the limit with every attempt until the limit is decrease to zero.  When the limit is reached, it does the next best thing, which is to reload the application.  If the chunk files for the current version of the application are still available, the retry logic should be able to solve the problem. Otherwise, a page reload takes place to download the application with the updated chunk information.

Code Gists

Route Loader Gist

Routes Gist

Conclusion

For this simple implementation, we decided to reload the application when a retry continues to fail. Depending on the use-case, the approach can be different. For example, a nice message can be displayed to the user explaining that a new update is available, and the application needs to be updated. This is the best user experience as feedback is provided to the user.

An important concern to consider when using Code Splitting is that a ChuckLoadError can take place for users with network issues or when a new update is pushed to production. Therefore, additional design and architecture considerations must be thought of before just adding the code splitting performance improvement to a React single page application.

Thanks for reading.

Originally published by ozkary.com