首页 文章

动态选择使用webpack在构建时加载哪个模块

提问于
浏览
2

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

目标是,如果您需要公共代码库并运行应用程序而不进行任何更改,您将获得应用程序的vanilla版本,但如果您在本地定义组件(例如Logo.jsx),则应用程序应使用该Logo.jsx的版本,而不是底层代码库中的默认组件 .

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

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

function importCustomOrDefaultComponent(name) {
  // check for a component with this name in the local project, and if so, return
  // if no local component exists, return the default component from this repo
}

module.exports = importCustomOrDefaultComponent;

在底层代码库中的所有组件中使用该自定义import语句(例如 NavBar 组件):

import React from 'react';
const importCustomOrDefaultComponent = require('../importCustomOrDefaultComponent.js');
const Logo = importCustomOrDefaultComponent('Logo.jsx')

function NavBar () {
  return (
    <div>
       ...
       <Logo />
       ...
    </div>
  );
};

export default NavBar;

我一直在摆弄它,似乎没有可能像我上面概述的那样,因为webpack不会让你使用这样的自定义导入语句来影响它如何构建依赖项 . 我尝试使用'fs'来编写 importCustomOrDefaultComponent 以查找自定义文件,但是在浏览器中没有't work because webpack tried to bundle the function in with everything else and ultimately I got an error because ' fs'...它似乎只能使用 require('xxx')import xxx from 'xxx' . 以上是可行的,如果是这样的话, importCustomOrDefaultComponent(name) 将如何运作?

如果这不能通过源中的自定义导入功能来完成,可以通过webpack插件完成吗?我无法找到任何处理这种情况的人 .

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

  • 我已经研究过代码拆分,但是当它拆分代码时,它似乎没有提供一个解决方案,能够动态选择是否在构建时包含组件A或组件B.

  • 我还考虑过追求一种插件架构,其中自定义组件以redux状态存储,并且可以动态访问客户端,而不是在构建客户端包时尝试做出这些决定 . 这是一个更好的方法吗?

1 回答

  • 2

    我将在今晚晚些时候用例子重写我的回复,现在这将是我的直接建议:
    对于webpack别名或preprocess-loader(以及ifdef语句)来说,这看起来是一个很好的用例 . 对于React Native,只能使用Babel插件,这是另一个故事 .
    就个人而言,我喜欢使用babel-plugin-module-alias来支持带有react-native-web目标的React Native .

    更新:(如承诺的那样)

    Code Splitting (Load Static Modules Dynamically)

    由于您使用的是Webpack,因此您需要考虑供应商模块 . 动态加载的最简单方法是通过Webpack的 require() 进行代码拆分 . 自 this method is async 以来,您的周围代码无法同步加载模块 .

    例:

    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>
            )
        }
    }
    

    注意:在旧版本的Webpack中,使用了 require.ensure() .

    Using Conditional Compilation

    使用 preprocess-loader ,您可以在构建时定义不同的常量 . 这也允许在 import 之类的顶级语句周围进行条件登录,这些语句不能在块作用域内使用 . 请记住 preprocess 确实将 @ifdef 视为真实,无论其 Value 如何,有些情况下您可能需要使用 @if .

    例:

    // @if MOBILE=true
    import Header from 'components/MobileHeader.js'
    // @endif
    // @if MOBILE=false
    import Header from 'components/DesktopHeader.js'
    // @endif
    

    Using Webpack Aliases

    在你的Webpack配置中:

    resolve: {  
        alias: {
            components: path.resolve(__dirname, 'src/components/'),
            'components/Header': path.resolve(__dirname, IS_MOBILE ? 'src/components/MobileHeader' : 'src/components/DesktopHeader')
        }
    }
    

    在你的JS里面(来自任何文件,任何目录):

    import Header from 'components/Header';
    

相关问题