Failed to fetch dynamically imported module:

Viewed 3226

I have a few React components that are lazy imported in App.tsx. App.tsx is used in Index.tsx where it is rendered and appended to the body.

   const IndexPage = lazy(() => import("../features//IndexPage"));
    const TagsPage = lazy(
      () => import("../features/tags/TagsPage")
    );
    const ArticlePage = lazy(() => import("../features/article/ArticlePage"));

    const SearchResultPage = lazy(
      () => import("../features/search-result/SearchResultPage")
    );

    const ErrorPage = lazy(() => import("../features/error/ErrorPage"));

    ----

    <BrowserRouter basename={basename}>
      <Suspense fallback={<Fallback />}>
        <Routes>
          <Route path={INDEX} element={<IndexPage />} />
          <Route path={ARTICLE} element={<ArticlePage />} />
          <Route path={TAGS} element={<TagsPage />} />
          <Route path={SEARCH} element={<SearchResultPage />} />
          <Route path={ERROR} element={<ErrorPage />} />
          <Route path="/*" element={<ErrorPage />} />
        </Routes>
      </Suspense>
    </BrowserRouter>

Often, the following error happens in production.

Failed to fetch dynamically imported module:

It has happened in all routes.

 https://help.example.io/static/js/SearchResultPage-c1900fe3.js

 https://help.example.io/static/js/TagsPage-fb64584c.js

 https://help.example.io/static/js/ArticlePage-ea64584c.js

 https://help.example.io/static/js/IndexPage-fbd64584c.js

I have changed the build path. Therefore, it is /static/js.

  build: {
    assetsInlineLimit: 0,
    minify: true,
    rollupOptions: {
      output: {
        assetFileNames: (assetInfo) => {
          var info = assetInfo.name.split(".");
          var extType = info[info.length - 1];
          if (/png|jpe?g|svg|gif|tiff|bmp|ico/i.test(extType)) {
            extType = "img";
          } else if (/woff|woff2/.test(extType)) {
            extType = "css";
          }
          return `static/${extType}/[name]-[hash][extname]`;
        },
        chunkFileNames: "static/js/[name]-[hash].js",
        entryFileNames: "static/js/[name]-[hash].js",
      },
    },
    outDir: "./../backend/src/main/resources/static/articles/",
    emptyOutDir: true,
  },

Does someone know how to fix this issue?

Update:

I have never got this error in development. I use Sentry to track errors. It has happened at least 274 times in two months.

This is all that is on Sentry.

{
  arguments: [
    {
      message: Failed to fetch dynamically imported module: https://help.example.io/static/js/SearchResultPage-c1900fe3.js,
  name: TypeError,
    stack: TypeError: Failed to fetch dynamically imported module: https://help.example.io/static/js/SearchResultPage-c1900fe3.js
  }
],
  logger: console 
}

Update

We had 500000 visits in the past two months. It happened 274 times. Since tracesSampleRate is 0.3, it is definitely more than that.

  Sentry.init({
    dsn: "",
    integrations: [new BrowserTracing()],
    tracesSampleRate: 0.3,
  });

It has happened on all kinds of browsers but mostly on Chrome.

I can not reproduce it either in dev nor in prod.

Update

I reproduced this bug finally. It happens if you are on a page and you release a new version. The file that contains the dynamically imported module, does not exist anymore, for eg:

https://help.example.io/static/js/IndexPage-fbd64584c.js

The above link returns 404.

3 Answers

It's hard to directly answers this question without all the data but I'll try to do my best and share a few ressources regarding that.

As discussed in the comments, there could be MANY reasons to why this happens. Since you can't reproduce, and it's not constant, we can probably exclude the theory where it's coming from your code or your deploy configs.

A few reasons on top of my head:

  • Network being slow at that moment when trying to fetch the resource. You could try to reproduce by throttling your network.
  • Parsing error or encountered an exception

I believe this error is similar to the 'ChunkLoadError' ( which is also faced in many other framework, not just React), attaching a similar question: Webpack code splitting: ChunkLoadError - Loading chunk X failed, but the chunk exists, note as well the same amount of traffic failing etc.

One attempt to fix this issue, try to catch the error and force a reload to refetch the resource, but make sure to not loop there.

I hope this helps.

Here are a few alternative takes on the issue.

Avoiding the issue altogether.

This is stating the obvious, and I suspect that this may not be a desirable answer from your perspective, but switching to static imports will fix your issue.

In many cases, the bundle size, even with static imports, will still be small enough not to affect your user experience, and definitely less so than encountering the error.

It is also arguably the only guaranteed way to solve it as even if your issue is caused by a malfunction somewhere that you manage to track down and fix, there are still legitimate situation where this issue can happen.

Managing the error elegantly

On the other hand, still in the mind-set that the error can and will still happen, React has the concept of ErrorBoundaries which you can leverage to deal with the user experience when it occurs : https://reactjs.org/docs/error-boundaries.html and https://reactjs.org/docs/code-splitting.html#error-boundaries

Taking matters into your own hands

Finally, the React lazy expects a function that returns a promise that resolves to a module. If it does not, well that's your TypeError. It is obviously intended to be used exactly like you did, but you are free to wrap that in something smarter if you wish. All you need to do is make sure that the promise eventually resolves to the imported module. For inspiration, see here for quite a few takes on retrying promises. Promise Retry Design Patterns

I had the same issue when migrating from cra to vite and deploying it to netlify. There was no problem traversing through non-lazy components, but error occurs when trying to load the lazy ones even though it didn't occur when running it on my local computer (with vite & vite build).

If by any chance you're deploying to netlify, I had to turn off assets optimization and redeploy the application in order for the lazy components to load properly. If not, maybe a different set of settings similar to bundling or minify need to be turned off.

Related