Alan
Alan

Reputation: 10125

White page after fresh build using React Route-based code splitting

The app is using react and React Route-based code splitting: https://reactjs.org/docs/code-splitting.html#route-based-code-splitting

The app is working fine. A user is on the homepage. Then I do a change in the code and build the app again.

User is clicking on a link, and he is landing on a white page. Of course, the bundle has changed, and loading the new page (thanks to React.lazy) will drop an error.

enter image description here Uncaught SyntaxError: Unexpected token <

How can I prevent that and show for example: "Site has been updated, please reload" instead of a white page?

Upvotes: 3

Views: 388

Answers (2)

bluedevil2k
bluedevil2k

Reputation: 9491

This is built off Alan's comment, which doesn't quite solve the problem of the original question. I faced a similar issue where a build done on a server changed all the file names of the bundles I was loading using React.lazy() and a user who didn't refresh their page would be looking for bundles that no longer exists, resulting in the error he describes.

Again, this is mostly based off Alan's code but solves the problem nicely...

export default function lazyReloadOnFail(fn) {
  return new Promise(resolve => {
    fn()
      .then(resolve)
      .catch(() => {
        window.location.reload();
      });
  });
}


const Report = React.lazy(() => lazyReloadOnFail(() => import('./views/Reports/Report')));

Upvotes: 1

Alan
Alan

Reputation: 10125

Solution is:

Did you know that the import(...) function that we use on lazy is just a function that returns a Promise? Which basically means that you can chain it just like any other Promise.

function retry(fn, retriesLeft = 5, interval = 1000) {
  return new Promise((resolve, reject) => {
    fn()
      .then(resolve)
      .catch((error) => {
        setTimeout(() => {
          if (retriesLeft === 1) {
            // reject('maximum retries exceeded');
            reject(error);
            return;
          }

          // Passing on "reject" is the important part
          retry(fn, retriesLeft - 1, interval).then(resolve, reject);
        }, interval);
      });
  });
}

Now we just need to apply it to our lazy import.

// Code split without retry login
const ProductList = lazy(() => import("./path/to/productlist"));

// Code split with retry login
const ProductList = lazy(() => retry(() => import("./path/to/productlist")));

If the browser fails to download the module, it'll try again 5 times with a 1 second delay between each attempt. If even after 5 tries it import it, then an error is thrown.

Thanks to Guilherme Oenning from: https://dev.to/goenning/how-to-retry-when-react-lazy-fails-mb5

Upvotes: 1

Related Questions