loadable-components icon indicating copy to clipboard operation
loadable-components copied to clipboard

Is it possible to fully dynamically load external package component ?

Open marckraw opened this issue 3 years ago • 6 comments

We have a component library. We are trying to load a component with dynamic name. It doest work when i try to load it from node_modules, but it works when i try to load local files

This guy works

const AsyncComponent = loadable(
    (props) => {
        return import(`./${props.icon}`)
    }
);

This guy doesnt work

const AsyncComponent = loadable(
    (props) => {
        return import(`@amazing/componentlib/${props.icon}`)
    }
);

So my question is, is it possible to load dynamically files from node_modules ?

(doing it in nextjs)

Also, to make clear, the problem is with dynamically constructed imports, this guy, works without problems:

const AsyncComponent = loadable(
    props => 
        import(`@amazing/componentlib/IconAirplane`)
)

marckraw avatar Oct 25 '22 06:10 marckraw

There is nothing special in loadable code capable to distinguish between your code and node_modules. However, I never tried loading stuff like in your example.

Can I ask for clarification - what does mean "This guy doesnt work"? How exactly?

theKashey avatar Oct 30 '22 08:10 theKashey

Probably off-topic, but what I noticed is if you use this construction in a loop:

const AsyncIcon = loadable(
  // this import resolves only for the 1st icon in the list which is the component "A" (see below)
  (props) => import(`./${props.icon}`),
  {
    resolveComponent(module, props) {
      // here you'll receive the icon name from each `map` iteration ("A", then "B", and "C" in the last call)
      const { icon } = props;
  
      // in case the module doesn't use a `default` export you have to take it by its key.
      // however, this will fail because the module is always "A", but on the second step you expect it as "ModuleB.B"
      return module[icon];
    },
  }
);

and then

const icons = ["A", "B", "C"];

<>
  {icons.map(icon => <AsyncIcon key={icon} icon={icon} /> }
</>

I was able to "solve" it via () => import("./index") where you can re-export all the icons so in the consequent resolveComponent function calls you can reference to IndexModule.A, IndexModule.B, ... module[icon] without errors. But the resulting chunk will contain all the icons reexported from the index file. Imagine you have 100 icons there if you need only 3 of them.

bashjs avatar Jan 06 '23 12:01 bashjs

A little off-topic, but however, this will fail because the module is always "A" sounds like a bug

theKashey avatar Jan 09 '23 05:01 theKashey

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.

stale[bot] avatar Apr 02 '23 19:04 stale[bot]

I have the same problem. Dynamic path doesnt work, hardcoded one does. Both are in src/, so no node_modules complexity.

This works:

const C = loadable(() => import('../screens/Test')

This doesnt work:

const componentPath = props.match.route.compPath // ../screens/Test
const C = loadable(() => import(`${componentPath}`))

It does not find the module... Cannot find module '../screens/Test'. Im using webpack 5.

Webpack shows Critical dependency: the request of a dependency is an expression and loadable-components throw this error: https://github.com/gregberge/loadable-components/blob/main/packages/component/src/createLoadable.js#L106-L113

pavelloz avatar May 26 '23 19:05 pavelloz

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.

stale[bot] avatar Aug 13 '23 01:08 stale[bot]