You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by su...@apache.org on 2020/08/10 23:31:38 UTC

[incubator-superset] 01/06: first attempts at dynamic plugin loading

This is an automated email from the ASF dual-hosted git repository.

suddjian pushed a commit to branch dynamic-plugin-import
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git

commit 9b0dfc4f54159b23054a6d57a95c6fc9b3af2e65
Author: David Aaron Suddjian <aa...@gmail.com>
AuthorDate: Wed Jun 10 14:30:03 2020 -0700

    first attempts at dynamic plugin loading
---
 superset-frontend/src/addSlice/App.tsx             |  5 +-
 .../DynamicPlugins/DynamicPluginProvider.tsx       | 40 +++++++++++++
 .../src/components/DynamicPlugins/PluginContext.ts | 25 +++++++++
 superset-frontend/src/welcome/App.tsx              | 65 +++++++++++-----------
 4 files changed, 103 insertions(+), 32 deletions(-)

diff --git a/superset-frontend/src/addSlice/App.tsx b/superset-frontend/src/addSlice/App.tsx
index 4443fb5..f94b4da 100644
--- a/superset-frontend/src/addSlice/App.tsx
+++ b/superset-frontend/src/addSlice/App.tsx
@@ -21,6 +21,7 @@ import { hot } from 'react-hot-loader/root';
 import { supersetTheme, ThemeProvider } from '@superset-ui/style';
 import setupApp from '../setup/setupApp';
 import setupPlugins from '../setup/setupPlugins';
+import DynamicPluginProvider from '../components/DynamicPlugins/DynamicPluginProvider';
 import AddSliceContainer from './AddSliceContainer';
 
 setupApp();
@@ -33,7 +34,9 @@ const bootstrapData = JSON.parse(
 
 const App = () => (
   <ThemeProvider theme={supersetTheme}>
-    <AddSliceContainer datasources={bootstrapData.datasources} />
+    <DynamicPluginProvider>
+      <AddSliceContainer datasources={bootstrapData.datasources} />
+    </DynamicPluginProvider>
   </ThemeProvider>
 );
 
diff --git a/superset-frontend/src/components/DynamicPlugins/DynamicPluginProvider.tsx b/superset-frontend/src/components/DynamicPlugins/DynamicPluginProvider.tsx
new file mode 100644
index 0000000..ca45e66
--- /dev/null
+++ b/superset-frontend/src/components/DynamicPlugins/DynamicPluginProvider.tsx
@@ -0,0 +1,40 @@
+import React, { useEffect, useState } from 'react';
+// use scriptjs for browser-side dynamic importing
+// import $script from 'scriptjs';
+// import { Preset } from '@superset-ui/core';
+import PluginContext, { initialPluginContext } from './PluginContext';
+
+console.log('from superset:', React);
+
+// In future this should be provided by an api call
+const pluginUrls = ['http://localhost:8080/main.js'];
+
+export type Props = React.PropsWithChildren<{}>;
+
+export default function DynamicPluginProvider({ children }: Props) {
+  const [pluginState] = useState(initialPluginContext);
+  useEffect(() => {
+    console.log('importing test');
+    // $script(pluginUrls, () => {
+    //   console.log('done');
+    // });
+    Promise.all(
+      pluginUrls.map(async url => {
+        const { default: d } = await import(/* webpackIgnore: true */ url);
+        return d;
+      }),
+    ).then(pluginModules => {
+      console.log(pluginModules);
+      // return new Preset({
+      //   name: 'Dynamic Charts',
+      //   presets: [],
+      //   plugins: [pluginModules],
+      // });
+    });
+  }, [pluginUrls]);
+  return (
+    <PluginContext.Provider value={pluginState}>
+      {children}
+    </PluginContext.Provider>
+  );
+}
diff --git a/superset-frontend/src/components/DynamicPlugins/PluginContext.ts b/superset-frontend/src/components/DynamicPlugins/PluginContext.ts
new file mode 100644
index 0000000..100e813
--- /dev/null
+++ b/superset-frontend/src/components/DynamicPlugins/PluginContext.ts
@@ -0,0 +1,25 @@
+import React from 'react';
+
+export enum LoadingStatus {
+  LOADING = 'loading',
+  COMPLETE = 'complete',
+  ERROR = 'error',
+}
+
+export type PluginContextType = {
+  status: LoadingStatus;
+  error: null | {
+    message: string;
+  };
+  pluginKeys: string[];
+};
+
+export const initialPluginContext: PluginContextType = {
+  status: LoadingStatus.LOADING,
+  error: null,
+  pluginKeys: [],
+};
+
+const PluginContext = React.createContext(initialPluginContext);
+
+export default PluginContext;
diff --git a/superset-frontend/src/welcome/App.tsx b/superset-frontend/src/welcome/App.tsx
index 5bc624d..c72a131 100644
--- a/superset-frontend/src/welcome/App.tsx
+++ b/superset-frontend/src/welcome/App.tsx
@@ -20,7 +20,7 @@ import React from 'react';
 import { hot } from 'react-hot-loader/root';
 import thunk from 'redux-thunk';
 import { createStore, applyMiddleware, compose, combineReducers } from 'redux';
-import { Provider } from 'react-redux';
+import { Provider as ReduxProvider } from 'react-redux';
 import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
 import { QueryParamProvider } from 'use-query-params';
 import { initFeatureFlags } from 'src/featureFlags';
@@ -38,6 +38,7 @@ import setupApp from '../setup/setupApp';
 import setupPlugins from '../setup/setupPlugins';
 import Welcome from './Welcome';
 import ToastPresenter from '../messageToasts/containers/ToastPresenter';
+import DynamicPluginProvider from 'src/components/DynamicPlugins/DynamicPluginProvider';
 
 setupApp();
 setupPlugins();
@@ -58,40 +59,42 @@ const store = createStore(
 );
 
 const App = () => (
-  <Provider store={store}>
+  <ReduxProvider store={store}>
     <ThemeProvider theme={supersetTheme}>
       <FlashProvider common={common}>
-        <Router>
-          <QueryParamProvider ReactRouterRoute={Route}>
-            <Menu data={menu} />
-            <Switch>
-              <Route path="/superset/welcome/">
-                <ErrorBoundary>
-                  <Welcome user={user} />
-                </ErrorBoundary>
-              </Route>
-              <Route path="/dashboard/list/">
-                <ErrorBoundary>
-                  <DashboardList user={user} />
-                </ErrorBoundary>
-              </Route>
-              <Route path="/chart/list/">
-                <ErrorBoundary>
-                  <ChartList user={user} />
-                </ErrorBoundary>
-              </Route>
-              <Route path="/tablemodelview/list/">
-                <ErrorBoundary>
-                  <DatasetList user={user} />
-                </ErrorBoundary>
-              </Route>
-            </Switch>
-            <ToastPresenter />
-          </QueryParamProvider>
-        </Router>
+        <DynamicPluginProvider>
+          <Router>
+            <QueryParamProvider ReactRouterRoute={Route}>
+              <Menu data={menu} />
+              <Switch>
+                <Route path="/superset/welcome/">
+                  <ErrorBoundary>
+                    <Welcome user={user} />
+                  </ErrorBoundary>
+                </Route>
+                <Route path="/dashboard/list/">
+                  <ErrorBoundary>
+                    <DashboardList user={user} />
+                  </ErrorBoundary>
+                </Route>
+                <Route path="/chart/list/">
+                  <ErrorBoundary>
+                    <ChartList user={user} />
+                  </ErrorBoundary>
+                </Route>
+                <Route path="/tablemodelview/list/">
+                  <ErrorBoundary>
+                    <DatasetList user={user} />
+                  </ErrorBoundary>
+                </Route>
+              </Switch>
+              <ToastPresenter />
+            </QueryParamProvider>
+          </Router>
+        </DynamicPluginProvider>
       </FlashProvider>
     </ThemeProvider>
-  </Provider>
+  </ReduxProvider>
 );
 
 export default hot(App);