使用动态导入JavaScript时出现“找不到模块”错误

8
我正在使用Create-React-App,并希望使用webpack 2.0支持的动态import()根据变量字符串导入模块。
我已经查看了官方提案(https://github.com/tc39/proposal-dynamic-import),似乎可以做到这样:
import(`./language-packs/${navigator.language}.js`)

但是当我尝试类似的东西时,它会出错。

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;

损坏的 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;

错误:

enter image description here

当我把LazyLoader更改为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;

它有效。

enter image description here

绝对路径是通过环境变量在create-react-app中构建的内容。
.env文件。
NODE_PATH=src/

我需要以这种方式动态加载模块,以构建多租户的概念验证。我该如何修复损坏的LazyLoad组件,以便可以传递一个字符串作为属性,并使LazyLoad组件从该字符串属性动态加载组件?

你尝试过将路径字符串'./pages/default/HomePage'作为路径,而不是pages/default/HomePage吗? - Michael Lyons
刚刚尝试了一下使用"./pages"、"../pages"和"../../pages",但是仍然出现了相同的错误。 - Kyle Truong
嗯,或许去掉句号,/pages...,不然我也不知道。关于打包分离,我使用React-Router的getComponent,并且使用require.ensure。抱歉,我没有通过import进行懒加载的经验。 - Michael Lyons
1
你是否发现 require.ensure 适用于插值字符串或表达式,而不是普通字符串? - Kyle Truong
是的,我刚刚尝试了一个字符串字面值,并且它被正确地评估了。你从哪里尝试获取这个字符串呢?是来自构建环境变量?还是基于 API 调用的客户端?这里有一个很好的例子:Github - Michael Lyons
1个回答

18

只有部分动态语句可以用于import()。

在你的AppRoutes.js文件中,你可以这样做:

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

然后在您的LazyLoad组件中,您需要执行:

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

完全动态的语句(例如import(foo))将失败,因为webpack需要至少一些文件位置信息。import()必须包含有关模块位置的至少一些信息,以便可以将捆绑限制为特定目录或文件集。

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


1
以防有人想知道,动态 require 语句也适用同样的规则。 - Pubudu Dodangoda

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接