Javascript 使用webpack动态选择在生成时加载哪个模块

Javascript 使用webpack动态选择在生成时加载哪个模块,javascript,reactjs,plugins,webpack,Javascript,Reactjs,Plugins,Webpack,我正在开发一个web应用程序,其中我需要本地定义的React组件来“重写”(即优先于)公共代码库中的默认React组件。本地应用程序需要公共代码库作为依赖项,它提供服务器代码和默认组件 我们的目标是,如果您需要公共代码库并在不做任何更改的情况下运行应用程序,您将获得一个普通版本的应用程序,但是如果您在本地定义一个组件(例如Logo.jsx),那么应用程序应该使用该版本的Logo.jsx,而不是底层代码库中的默认组件 我的第一个想法是通过在底层代码库中的所有组件中使用动态导入语句来解决这个问题,这

我正在开发一个web应用程序,其中我需要本地定义的React组件来“重写”(即优先于)公共代码库中的默认React组件。本地应用程序需要公共代码库作为依赖项,它提供服务器代码和默认组件

我们的目标是,如果您需要公共代码库并在不做任何更改的情况下运行应用程序,您将获得一个普通版本的应用程序,但是如果您在本地定义一个组件(例如Logo.jsx),那么应用程序应该使用该版本的Logo.jsx,而不是底层代码库中的默认组件

我的第一个想法是通过在底层代码库中的所有组件中使用动态导入语句来解决这个问题,这样在构建时webpack将只查找组件的本地版本,然后在依赖关系图中包含本地版本,或者使用回退组件。在伪代码中,此解决方案的理想版本如下所示:

定义自定义导入语句(
importCustomOrDefaultComponent.js
):

在基础代码库的所有组件(例如
NavBar
组件)中使用该自定义导入语句:

从“React”导入React;
const importCustomOrDefaultComponent=require('../importCustomOrDefaultComponent.js');
const Logo=importCustomOrDefaultComponent('Logo.jsx')
函数导航栏(){
返回(
...
...
);
};
导出默认导航栏;
我一直在摆弄这一点,似乎不可能像我上面概述的那样做,因为webpack不允许您使用像这样的自定义导入语句来影响它如何构建依赖项。我尝试使用“fs”来编写
importCustomOrderFaultComponent
以查找自定义文件,但这不起作用,因为webpack试图将函数与其他所有内容捆绑在一起,最终我遇到了一个错误,因为“fs”在浏览器中不可用。。。似乎您只能使用
require('xxx')
从'xxx'导入xxx
。是否可以执行上述操作?如果可以,该
importCustomOrderFaultComponent(名称)
将如何操作

如果这不能通过源代码中的自定义导入功能完成,那么可以通过网页包插件完成吗?我找不到任何人来处理这个案子

如果这不起作用,是否有其他模式来实现我的目标

  • 我已经研究过代码拆分,但是虽然它拆分了代码,但它似乎没有提供一个解决方案,以便能够在构建时动态选择是包含组件a还是组件B
  • 我还考虑采用插件体系结构,其中自定义组件存储在redux状态,并在客户端动态访问,而不是在构建客户端包时尝试做出这些决定。这是更好的方法吗
今晚晚些时候,我将用示例改写我的回答,因为现在这将是我的直接建议:

对于网页包别名或预处理加载程序(以及ifdef语句),这看起来是一个很好的用例。对于React Native,只能使用Babel插件,这完全是另一回事

就个人而言,我喜欢使用babel插件模块别名来支持React-Native和React-Native web目标

更新:(如承诺的那样)

代码拆分(动态加载静态模块)

由于您使用的是Webpack,因此需要考虑供应商模块。 进行动态加载的最简单方法是通过网页包的
require()
进行代码拆分。由于此方法是异步的,因此周围的代码无法同步加载模块

例如:

class SomeView extends Component {
    state = {
        asyncComponent: null
    };

    componentDidMount() {
        import(/* webpackChunkName: "asyncComponent" */ './asyncComponent.jsx')
            .then((asyncComponent) => this.setState({ asyncComponent }));
    }

    render() {
        const AsyncComponent = this.state.asyncComponent;

        return (
            <div>
                {AsyncModule !== null ? <AsyncModule /> : null}
            </div>
        )
    }
}
// @if MOBILE=true
import Header from 'components/MobileHeader.js'
// @endif
// @if MOBILE=false
import Header from 'components/DesktopHeader.js'
// @endif
使用网页包别名

在您的网页包配置中:

resolve: {  
    alias: {
        components: path.resolve(__dirname, 'src/components/'),
        'components/Header': path.resolve(__dirname, IS_MOBILE ? 'src/components/MobileHeader' : 'src/components/DesktopHeader')
    }
}
在JS内部(来自任何文件、任何目录):


别名似乎可以通过webpack创建客户端包,是一个很好的干净解决方案。不幸的是,我还需要进行SSR,而别名会导致一个问题:当服务器启动时,它会对其中包含别名导入的组件抛出一个
找不到模块
错误,可能是因为它们没有网页包。如果无法避免SSR,选项似乎是(a)将整个服务器代码打包(似乎不理想)或(b)以某种方式将别名传递给服务器代码(可能通过babel polyfill与babel插件模块解析程序插件一起使用?)还有其他建议吗?我认为
模块别名
可能是为服务器代码创建别名的选项
// @if MOBILE=true
import Header from 'components/MobileHeader.js'
// @endif
// @if MOBILE=false
import Header from 'components/DesktopHeader.js'
// @endif
resolve: {  
    alias: {
        components: path.resolve(__dirname, 'src/components/'),
        'components/Header': path.resolve(__dirname, IS_MOBILE ? 'src/components/MobileHeader' : 'src/components/DesktopHeader')
    }
}
import Header from 'components/Header';