Reduce Unused JavaScript with Dynamic CMS Components

5th Nov 2021

Reduce Unused JavaScript with Dynamic CMS Components

I found in the bundle analysis that I was loading the CMS editor components into the _app chunk unnecessarily. I have been able to remove a lot of the JavaScript used but not all. Still, this has made a big impact to the chunk size as well as the performance scores.

Bundle Analyzer Shows no Editor JavaScript
Bundle Analyzer Shows no Editor JavaScript

The key ingredient to these changes has been using the next/dynamic util. The hardest part of this work has been to work out what functionality was needed to render the page outside of "editing" mode and secondly how best to use import to only include the functionality I am using.

Minimal CMS Context

As I have mentioned, my app uses tinacms and it needs the TinaProvider and (in my case) the TinacmsGithubProvider even when we are not editing. Unfortunately this also means that I have had to pull in the TinaCMS class from tinacms but I can instantiate it with a minimal config when we are not editing.

const cms = useMemo(() => {
const tinaConfig = {
enabled: false,
toolbar: false,
sidebar: false,
}
return new TinaCMS(tinaConfig)
}, [])

This has removed react-tinacms-editor (this biggie), next-tinacms-github and @tinacms/browser-storage from the _app imports.

AppEditMode Component

I have moved all the edit mode functionality into a separate file which exposes a single component AppEditMode. This has meant that I can dynamically import this component when it is needed. Dynamically importing it looks like this:

Use dynamic function to generate a local component based on the external import.

import dynamic from 'next/dynamic'
const AppEditMode = dynamic(
() => import('../src/cms/AppEditMode'),
{ ssr: false }
)

Conditionally render the component based on whether we are in preview mode.

if (pageProps.preview) {
return (
<AppEditMode
preview={pageProps.preview}
error={pageProps.error}
>
<Component {...pageProps} />
</AppEditMode>
)
} else {
// ...
}

The AppEditMode.tsx can now import what it needs without affecting the _app chunk size.

Performance Scores Update

So it is time to see what impact this work has made on the lighthouse performance scores in web.dev/measure. I have already seen the output from bundle-analyzer (above) shows less JavaScript in the chunk.

Now performance is 97! That is quite a jump and a worthwhile bit of work.

Lighthouse Performance Score 97 After Dynamically importing CMS
Lighthouse Performance Score 97 After Dynamically importing CMS

This series: