I have an application which uses React/Redux. I use Electron to package it as a standalone app. I am currently working on building the base to allow users to add their own plugin or widget to the app. Since I'm using Redux, I would like to keep using Redux to keep track of what is installed and the changes/new functionality it brings to the application.
Before I dive into my question, let's take an example. My core application has a sidebar with "control" buttons. The core has two buttons, but I'd like to allow plugins to add their own buttons there. Of course, manually I could go ahead, import the plugin in the js file of the button sidebar component and add the buttons manually, but this would defeat the pluggability purpose. So the best and most simple solution I can think of is to dispatch an action from the plugin code, such as ADD_SIDEBAR_BUTTON which basically adds an object with the metadata of the button to an array of buttons (including those that are core.) Something like this:
store.dispatch({type: "ADD_SIDEBAR_BUTTON", payload: {type: "button", path: "goSomewhere", label: "A label"}});
While this can work, it limits what the button can do greatly, as the actual logic and jsx for the button will come from the core application. In practice, I'm just itching to have the plugin pass a React component, which would give the plugin much freedom in terms of events, full control of the lifecycle, etc, ... But passing anything else than plain objects is a Redux no-no.
Another solution would be to let plugin developers create a file, with an exported class, and provide the path to it with redux, as follows:
class MyPluginButton extends Component {
handleClick() => evt => {
// do my special things
}
render() {
return <button onClick={this.handleClick}>My Special Button</button>
}
}
export default MyPluginButton;
An initialize() function of the plugin would then dispatch the action and pass the information needed for the core to import the button (I can also think of security issues with this potentially if not done properly):
store.dispatch({type: "ADD_SIDEBAR_BUTTON", payload: {path: "myplugin/src/components/MyPluginButton"}});
Now to my question, does anyone have good ideas how this could/should be implemented? I want to make sure there's no other pattern or implementation I have missed.