簡體   English   中英

動態加載 React 組件

[英]Dynamically loading React components

我正在考慮構建一個 Web 應用程序,人們可以在其中安裝插件。 我希望插件能夠定義將呈現到頁面的 React 組件,而無需在安裝插件后重新編譯主 JavaScript 包。

所以這是我正在考慮的方法:

  • 使用 webpack 將主要 JavaScript 與 React 作為外部庫捆綁在一起。
  • 讓插件作者也使用 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

這是幾個月前我在客戶工作中也面臨的一個有趣問題,我沒有看到太多的文檔方法。 我們所做的是:

  1. 單個插件將是單獨的 Webpack 項目,我們為其提供模板或生成項目模板的 CLI 工具。

  2. 在這個項目中,我們為核心應用程序中已經使用的共享供應商庫定義了 Webpack externals :React、Redux 等。這告訴插件不要將它們包含在包中,而是從我們在核心應用程序中設置的window的變量中獲取它們. 我知道,聽起來很糟糕,但這比讓所有插件重新包含 1000 個共享模塊要好得多。

  3. 重用這個external概念,核心應用程序還通過 window 對象向插件提供了一些服務。 最重要的一個是PluginService.register()方法,您的插件在初始化時必須調用該方法。 我們在這里反轉控制:插件負責向核心應用程序說“嗨,我在這里,這是我的主要導出(組件,如果它是 UI 插件)”。

  4. 核心應用程序有一個 PluginCache 類/模塊,它只保存加載插件的緩存(pluginId -> 無論插件導出,fn,類,等等)。 如果某些代碼需要一個插件來呈現,它會向這個緩存請求它。 這樣做的好處是允許在插件未正確加載時返回<Loading /><Error />組件,等等。

  5. 對於插件加載,這個 PluginService/Manager 加載插件配置(我應該加載哪些插件?)然后創建動態注入的script標簽來加載每個插件包。 當 bundle 完成時,第 3 步中描述的register調用將被調用,第 4 步中的緩存將包含該組件。

  6. 不要嘗試直接從您的組件加載插件,而是從緩存中請求它。

這是一個非常高級的概述,它與我們當時的需求密切相關(它是一個類似儀表板的應用程序,用戶可以在其中動態添加/刪除面板,並且所有這些小部件都是作為插件實現的)。

根據您的情況,您甚至可以使用<Provider store={ theCoreStore } > 包裝插件,以便它們必須訪問 Redux,或者設置某種事件總線,以便插件可以相互交互......有很多東西要提前弄清楚。 :)

祝你好運,希望它以某種方式有所幫助!

您可以導入一個 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

在一個類似的問題上提出了另一種方法 回顧:

在您的應用上

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;

在其他問題的頁面上查看更多詳細信息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM