question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

React Loadable Components increase Cumulative Layout Shift (CLS)

See original GitHub issue

After migrating a server side rendering React application to Loadable Components for code splitting and lazy loading, the initial bundle size, thus its download time, reduced as expected. However after replacing the classical React rendering method by the Loadable Components one, with the rest of the application code unchanged, my Cumulative Layout Shift score in PageSpeed / LightHouse raised to the sky, from 0.01 to 0.6 or more. What I am doing wrong?

SSR code before Loadable Components (good CLS score) :

Server-side :

...
import React from 'react'
import { renderToString } from 'react-dom/server'
import { StaticRouter } from 'react-router-dom'
...
const ssrApp = renderToString(
  <StaticRouter location={`/${this.requestedPage.uri}`} context={{}}>
    <App />
  </StaticRouter>
)

Client-side :

...
import React from 'react'
import { BrowserRouter } from 'react-router-dom'
import { hydrate } from 'react-dom'
...
hydrate(<BrowserRouter><App /></BrowserRouter>, appRoot)
...

SSR after Loadable Components (bad CLS score) :

Server-side :

...
import React from 'react'
import { renderToString } from 'react-dom/server'
import { StaticRouter } from 'react-router-dom'
import { ChunkExtractor } from '@loadable/server'
import path from 'path'
...
const statsFile = path.resolve(`${process.env.APP_ROOT}${path.sep}public${path.sep}js${path.sep}loadable-stats.json`)
const extractor = new ChunkExtractor({ statsFile, publicPath: '/js' })
const jsx = extractor.collectChunks(
  <StaticRouter location={`/${this.requestedPage.uri}`} context={{}}>
    <App user={currentUser} requestedPage={this.requestedPage} />
  </StaticRouter>
)
const scriptTags = extractor.getScriptTags()
const ssrApp = renderToString(jsx)
...

Client-side :

...
import React from 'react'
import { BrowserRouter } from 'react-router-dom'
import { hydrate } from 'react-dom'
import { loadableReady } from '@loadable/component'
...
loadableReady(() => { hydrate(<BrowserRouter><App /></BrowserRouter>, appRoot) })
...

Highlights:

  • Even with throttling to slow 3G, I don’t see any visible CLS with Loadable Components enabled.
  • According to PageSpeed and LightHouse, it’s the whole <main> section that is shifted, like if the SSR page is fully rendered dispite using hydrate.
  • The exact same code doesn’t lead to layout shift without Loadable Components.

Config:

"dependencies": {
    "@loadable/component": "^5.14.1",
    "@loadable/server": "^5.14.2",
    "bnc-libs": "^0.2.33",
    "cookie-parser": "^1.4.5",
    "express": "^4.17.1",
    "isomorphic-fetch": "^3.0.0",
    "lazysizes": "^5.3.1",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-router-dom": "^5.2.0"
  },
  "devDependencies": {
    "@babel/cli": "^7.13.10",
    "@babel/core": "^7.13.13",
    "@babel/plugin-proposal-class-properties": "^7.13.0",
    "@babel/preset-react": "^7.13.13",
    "@babel/preset-typescript": "^7.13.0",
    "@loadable/babel-plugin": "^5.13.2",
    "@loadable/webpack-plugin": "^5.14.2",
    "@types/express": "^4.17.11",
    "@types/isomorphic-fetch": "0.0.35",
    "@types/loadable__component": "^5.13.3",
    "@types/loadable__server": "^5.12.3",
    "@types/node": "^14.14.37",
    "@types/react": "^17.0.3",
    "@types/react-dom": "^17.0.3",
    "@types/react-router-dom": "^5.1.7",
    "babel-loader": "^8.2.2",
    "jshint": "^2.12.0",
    "ts-node": "^9.1.1",
    "ts-node-dev": "^1.1.6",
    "typescript": "^4.2.3",
    "webpack": "^5.28.0",
    "webpack-cli": "^4.5.0",
    "webpack-node-externals": "^2.5.2"
  }
}

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:1
  • Comments:11

github_iconTop GitHub Comments

3reactions
ludovic-lambertcommented, Mar 31, 2021

It takes 3 minutes to switch SSR from Loadable-components to a standard React.

1reaction
theKasheycommented, Mar 30, 2021

I don’t have extra time even to go and merge a few awesome PRs here, so no, I have not. And you are the first one who reported the issue, so there is still a chance that it is somehow bound to your particular usecase.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Loadable Components increase Cumulative Layout Shift (CLS ...
I am seeing the issue with React.lazy() & CLS. Removing React.lazy() improves CLS, but penalises with higher FCP, Speed Index & LCP. Adding...
Read more >
Optimize Cumulative Layout Shift - web.dev
Cumulative Layout Shift (CLS) is a metric that quantifies how often users experience sudden shifts in page content.
Read more >
The Duality of CLS with Lazy Loading Components
But caution: The same web app can cause Cumulative Layout Shift (CLS) on slower connections but runs without CLS on faster connection.
Read more >
How To Fix Cumulative Layout Shift (CLS) Issues
Cumulative Layout Shift (CLS) attempts to measure those jarring movements of the page as new content — be it images, advertisements, or ...
Read more >
How To Fix Cumulative Layout Shift (Examples & Best Practices)
The Cumulative Layout Shift (CLS) metric measures how much unexpected layout shifts affect the user experience on a page.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found