Loadable-components: Uncaught Error: Cannot find module

Created on 31 Mar 2020  路  8Comments  路  Source: gregberge/loadable-components

馃挰 Questions and Help

First off, thanks for the great library.

I am currently building a server-side rendered application, using Loadable Components (5.12.0) for 'component-level' code-splitting. The application contains a componentSwitch component which consumes an array of objects provided by a CMS - the component iterates over this array and returns a <Component /> for each object using an id key to target the relevant directory

const Component: LoadableComponent<any> = loadable(() =>
  import(`../presentation/${id}`)
)

return (
  <ErrorBoundary key={guid}>
    <Component {...data} />
  </ErrorBoundary>
)

This works just fine when the IDs returned from the server match-up to components in the application, but if the CMS returns an ID which doesn't have a matching component present in the application I get the following error;

Uncaught Error: Cannot find module './SomeComponent'

Initially I wrapped the Loadable import in a try/catch, but Loadable doesn't throw an error if the imported module cannot be found, instead it returns the following;

// console.log(SomeComponent) 
$$typeof: Symbol(react.forward_ref)
render: 茠 (props, ref)
preload: 茠 (props)
load: 茠 (props)

I attempted to hack around this by running the load method on the returned Loadable before returning the <Component /> from the switcher:

try {
  Component.load();
} catch (error) {
  return null;
}

This hack gets shut of the original error(s), but results in a server/client mismatch warning;

Warning: Expected server HTML to contain a matching <main> in <div>

Right now I am building an array[str] of IDs for each component present in the directory, e.g. ['Hero', 'Statement'] - I then check if the incoming ID is present in the array, if so create a Loadable, else return null. I am satisfied with this approach, however I would much prefer to check if the module exists in a more 'dynamic' fashion.

Any guidance will be very much appreciated.

All 8 comments

Hey @iamdcj :wave:,
Thank you for opening an issue. We'll get back to you as soon as we can.
Please, consider supporting us on Open Collective. We give a special attention to issues opened by backers.
If you use Loadable at work, you can also ask your company to sponsor us :heart:.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

I faced with a similar case, and I don't know how I can fix it.

Please can this be re-opened.

use import { lazy } from '@loadable/component' and loadable will throw an error __to a nearest Error boundary__, where you can react on it.

See https://loadable-components.com/docs/suspense/

I am currently building a server-side rendered application.

Suspense and Error boundaries are client-side only implementations.

I see. Right now in case of "module not found" during SSR loadable would _think_ - "oh, that is client-side, let's call import!"

So what is expected behaviour - be able to "try" file first (like Component.load();) or fallback to ErrorComponent?

I appreciate the reopening of the ticket, but it feels like my opening comment has been lost/ignored.

fallback to ErrorComponent?

I'm not sure if 'ErrorComponent' refers to a boundary, but boundaries do not catch on the server-side. If it was a client-side only solution this report wouldn't exist.

be able to "try" file first (like Component.load();)

My opening comment touches on this scenario;

I attempted to hack around this by running the load method on the returned Loadable before returning the from the switcher:

try {
  Component.load();
} catch (error) {
  return null;
}

This hack gets shut of the original error(s), but results in a server/client mismatch warning;

Warning: Expected server HTML to contain a matching <main> in <div>

I liked this approach; it allowed me to dynamically check a component existed in the codebase without maintaining an array of component IDs, however the server/client mismatch could not be ignored.

I am no longer engineering the application which prompted me to open this ticket, but others seem to be having similar issues. I can only really comment on what I wanted at the time, and that was the ability to have a component switch which loads a component using an CMS-generated, API-provided key(id), for example;

const someComponent = loadable(() => import(../presentation/${id})

If the API provided key is used to load a component from a directory which does not exist, then it is caught on the server and we simply return null.

It wasn't a hardship for me to maintain an array of known components, e.g. ['Hero', 'Statement']- this solution allowed me to check that the API provided key matches-up to an existing component in the application, and thus prevent any of the reported issues.

I didn't have the time to fork and figure out a solution back when I reported the issue, and I don't see me using loadable-components on the server any time soon. I will close this again, and let others report their specific issue.

Thanks again for the great work on Loadable Components, it is really appreciated.

Was this page helpful?
0 / 5 - 0 ratings