动态加载React组件

时间:2017-06-27 10:40:36

标签: javascript reactjs webpack

我正在考虑构建一个Web应用程序,人们可以在其中安装插件。我希望插件能够定义将呈现给页面的React组件,而无需在安装插件后重新编译主JavaScript包。

所以这就是我想到的方法:

  • 使用webpack将主要的JavaScript与React捆绑为external library
  • 让插件作者使用React编译他们的组件作为外部库。

这样,我只运行一个React实例。我可能会对其他一些常用的库做同样的事情。

问题是,如何从服务器动态加载这些插件组件。假设我有以下组件:

class PluginRenderer extends React.Component{
  componentWillMount() {
    getPluginComponent(`/plugins/${this.props.plugin}/component.js`).then((com) => {
      this.setState({pluginComponent: com});
    })
  }

  render() {
    var Plugin = this.state.pluginComponent;
    return Plugin ? <Plugin {...this.props} /> : "Loading..."
  }
}

如何实施getPluginComponent

3 个答案:

答案 0 :(得分:6)

这是我几个月前在客户工作中遇到的一个有趣的问题,我没有看到太多的文档方法。我们做的是:

  1. 单个插件将是单独的Webpack项目,我们为其提供生成项目模板的模板或CLI工具。

  2. 在这个项目中,我们为已经在核心应用程序中使用的共享供应商库定义了Webpack externals:React,Redux等。这告诉插件不要包含那些包中的那些,而是从中获取它们我们在核心应用中设置的window变量。我知道,听起来很糟糕,但它比让所有插件重新包含1000个共享模块要好得多。

  3. 重用external的这个概念,核心应用程序还通过窗口对象提供一些服务到插件。最重要的一个是PluginService.register()方法,插件在初始化时必须调用。我们在这里反向控制:插件有责任说&#34;嗨我在这里,这是我的主要导出(如果它是UI插件的组件)&#34;到核心应用程序。

  4. 核心应用程序有一个PluginCache类/模块,它只是为加载的插件保存一个缓存(pluginId - &gt;无论插件导出,fn,类等等)。如果某些代码需要一个插件来呈现,它会向此缓存请求它。这样做的好处是,当插件未正确加载时,允许返回<Loading /><Error />组件,依此类推。

  5. 对于插件加载,这个PluginService / Manager加载插件配置(我应该加载哪些插件?)然后创建动态注入的script标签来加载每个插件包。捆绑完成后,将调用步骤3中描述的register调用,并且步骤4中的缓存将包含该组件。

  6. 不是试图直接从组件加载插件,而是从缓存中请求插件。

  7. 这是一个非常高级别的概述,它与我们当时的要求非常相关(它是一个类似仪表板的应用程序,用户可以动态添加/删除面板,所有这些小部件都实现为插件)。 / p>

    根据您的情况,您甚至可以使用<Provider store={ theCoreStore }&gt;来封装插件。因此他们必须访问Redux,或者设置某种类型的事件总线,以便插件可以相互交互......有很多东西可以提前搞清楚。 :)

    祝你好运,希望它有所帮助!

答案 1 :(得分:1)

您可以导入一个HOC组件来执行此操作。组件作为微型应用程序动态加载到您的宿主应用程序中。

// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

window.React = React;
window.ReactDOM = ReactDOM;

ReactDOM.render(<App />, document.getElementById('root'));

// app.js
import React from 'react';
import ReactDOM from 'react-dom';
import MicroApp from '@schalltech/honeycomb-react-microapp';

const App = () => {
  return (
    <MicroApp
        config={{
          View: {
            Name: 'redbox-demo',
            Scope: 'beekeeper',
            Version: 'latest'
          }
        }}
      />
  );
});

export default App;

在设计时未安装或未知组件。如果您有创造力,则可以使用这种方法更新组件,而无需重新部署主机应用程序。

https://github.com/Schalltech/honeycomb-marketplace#using-micro-apps

答案 2 :(得分:0)

我提出了an alternative approach on a similar question。重新封底:

在您的应用上

import(/* webpackIgnore: true */'https://any.url/file.js')
  .then((plugin) => {
    plugin.main({ /* stuff from app plugins need... */ });
  });

在您的插件上...

const main = (args) => console.log('The plugin was started.');
export { main };
export default main;

查看更多详细信息on the other question's page