Code splitting our React app

Liam Tarpey
Busuu Tech
Published in
4 min readDec 18, 2019

--

I’m Liam, a Front-end engineer at Busuu, based in London, UK. We specialise in language learning and our goal is to break down barriers and empower everyone to learn a new language. In the web team, our primary focus is our Web app (our main learning platform, mainly React but some old bits are still being migrated away from Angular JS) but we also build and maintain a number of other projects — a marketing platform powered by a Grav CMS, an enterprise app and a few internal tools for our education and customer services teams.

I’m going to talk through how we dealt with code splitting in our Web app and some of the discoveries we made.

  1. Why we implemented code splitting
  2. Our code
  3. Object references

Why we implemented code splitting

We realised that over 55% of our JS bundle wasn’t being used on page load when you first access the app

Chrome dev tools has a handy tool called ‘coverage’ which helps you analyse what percentage of code is actually being used at a given time. As you navigate through the app and start interacting with different features, this percentage gradually drops.

Big chunks of our app were infrequently used by users when first accessing our app or even worse, only used once (Onboarding flow, Settings, User profile, Print exercises etc…) This means a slower experience for all users as our entire JS bundle needs to be fetched and parsed on first load of our app or every time the cache is invalidated after a new release.

Our code

A lot of articles have already gone into depth about React lazy, Suspense etc… so I won’t cover how that works in detail here, but would like to quickly share the challenges we faced.

The code snippets below are an example of how to implement code splitting into your React app at a very basic level.

  1. We define a list of loadable components:
This will tell Webpack that the files are meant to be decoupled from the main bundle. We used the dynamic import syntax here.

2. We create a higher-order component:

This HOC returns a class that renders the main component, the suspense component and the error boundary.

3. We create an error boundary:

The error boundary helps us catch any errors with the loading of the dynamic component or any other errors that occur in it’s child components

4. We import our component wherever we need it:

After implementation you should see that the ‘Home’ component now gets requested as a separate XHR request to the ‘main’ bundle in the network:

Object references

Here comes the interesting part. Unfortunately we couldn’t find any articles talking about shared code — for example ‘services’ or ‘factories’ that are imported into multiple dynamically loaded files.

We noticed that, in certain cases, a small service or factory would be duplicated into each of these files. This is fine if it’s just a duplicates small helper functions, but, in the case of us storing variables in this service/factory we’d end up with multiple declarations.

Addy Osmani & Jeremy Wagner wrote an interesting article on code splitting but the object reference topic was not covered. I reached out to them via Twitter to see how they approached this as they had the same issue in their example repository. As you can see, I wasn’t fully understanding what was happening with the duplicated code (as I thought the first reference was lost) until they replied to me.

Take this short video example:

Recap:

  • TestService is imported into two separate components (loadables) which are dynamically loaded as they need to be accessed within the app.
  • The two components are bundled into separate bundles but both include TestService
  • Danger Zone — We have number and user variables declared twice which surely means if they’re changed from the components that import them they’ll be out of sync with each other which is absolutely not what we want.

Luckily — Webpack has thought of this and we don’t end up facing this problem. It uses the reference of the service that is loaded first. In this example, if we land on the homepage and load HomeComponent.jsx , the subsequent declaration of test.service.js that gets declared inside AboutComponent.jsx is completely ignored and the first reference is used.

Always investigate what is going on behind the scenes with your code!
Take the time to dig a little deeper to truly understand it or you could face unexpected problems.

I hope this was useful to someone investigating code splitting. I fully recommend implementing this but ensure you don’t go too far that you end up with loadable components everywhere — you still want to preserve some kind of user experience. Do what makes sense for your project.

If you’d like to progress in your tech career and you’ve got a love for learning languages (tech or otherwise), we’ve got lots of open roles in our Tech team! Check out our latest jobs here.

--

--