Uncaught Error: Cannot Find Module When Using Dynamic Import for JavaScript

Kyle Truong picture Kyle Truong · May 24, 2017 · Viewed 9.2k times · Source

I'm using Create-React-App and am looking to use the dynamic import() supported by webpack 2.0 to import a module based on a variable string.

I've looked at the official proposal (https://github.com/tc39/proposal-dynamic-import) and it seems possible to do something like this:

import(`./language-packs/${navigator.language}.js`)

But it breaks when I try something similar.

AppRoutes.js

import LazyLoad from 'services/LazyLoad';

export class AppRoutes extends React.Component {
  render() {
    return (
      <Switch>
        <Route
          exact path="/"
          render={(matchProps) => (
            <LazyLoad
              absoluteModulePath='pages/default/HomePage'
              getComponent={() => import('pages/default/HomePage')}
              {...matchProps}
            />
          )}
        />
      </Switch>
    );
  }
}

export default AppRoutes;

pages/default/HomePage/index.js

import React from 'react';

export const HomePage = () => {
  return (
    <div>
      I'm the default HomePage
    </div>
  );
}

export default HomePage;

BROKEN services/LazyLoad/index.js

import React from 'react';

export class LazyLoad extends React.Component {
  ...

  componentDidMount() {
    import(this.props.absoluteModulePath)  // Critical dependency: the request of a dependency is an expression
      .then(module => module.default)
      .then(AsyncModule => this.setState({AsyncModule}))
  }

  ...
}

export default LazyLoad;

Error:

enter image description here

But when I change the LazyLoader to

WORKING services/LazyLoad/index.js

import React from 'react';

export class LazyLoad extends React.Component {
  ...

  componentDidMount() {
    this.props.getComponent()
      .then(module => module.default)
      .then(AsyncModule => this.setState({AsyncModule}))
  }

  ...
}

export default LazyLoad;

it works.

enter image description here

The absolute paths is something built into create-react-app with the help of environment variables.

.env

NODE_PATH=src/

I require dynamically loading modules this way to build a proof of concept for multi-tenancy. How can I fix the broken LazyLoad such that I can pass a string as a prop and have the LazyLoad component dynamically load the component from that string prop?

Answer

Mudiaga Ejenavi picture Mudiaga Ejenavi · Jul 13, 2017

Only partially dynamic statement are allowed for import().

In your AppRoutes.js you could do this:

...
<LazyLoad
    modulePath='HomePage'
    getComponent={() => import('pages/default/HomePage')}
    {...matchProps}
/>

then in your LazyLoad Component you do:

componentDidMount() {
  import(`pages/default/${this.props.modulePath}/index.js`)
    .then(module => module.default)
    .then(AsyncModule => this.setState({AsyncModule}))
}

Fully dynamic statements, such as import(foo), will fail because webpack requires at least some file location information.The import() must contain at least some information about where the module is located, so bundling can be limited to a specific directory or set of files.

https://webpack.js.org/api/module-methods/#import-