Requirements for Implementing Frontend Plugin Framework

Any up-to-date implementation details can now be found in the README.

1. Add @edx/frontend-plugin-framework as a dependency

https://www.github.com/openedx/frontend-plugin-framework

2. Micro-frontend configuration document (JS)

Micro-frontends that would like to use the plugin framework need to be configured via a JavaScript configuration document, and to include a new pluginSlots config.  

const config = {   // other existing configuration     plugins: {         sidebar: {            keepDefault: false, // bool to keep default host content        plugins: [           {           url: 'https://plugin.app/plugin1',           type: IFRAME_PLUGIN,         }       ]     }   } }

3. Host Micro-frontend (JSX)

Hosts must define PluginSlot components in areas of the UI where they intend to accept extensions.  The host MFE, and thus the owners of the host MFE, are responsible for deciding where it’s acceptable to mount a plugin.  They also decide the dimensions, responsiveness/scrolling policy, and whether the slot supports passing any additional data to the plugin as part of its contract.

<HostApp> <Route path="/page1"> <SomeHostContent /> <PluginSlot id="sidebar" pluginProps={{ className: 'flex-grow-1', title: 'example plugins', }} style={{ height: 700, }} > <DefaultSlotContent /> // removed if keepDefault is false </PluginSlot> </Route> <Route path="/page2"> <OtherRouteContent /> </Route> </HostApp>

4. Plugin Micro-frontend (JSX) and Fallback Behavior

The plugin MFE is no different than any other MFE except that it defines a Plugin component as a child of a route.  This component is responsible for communicating (via postMessage) with the host page and resizing its content to match the dimensions available in the host’s PluginSlot. 

It’s notoriously difficult to know in the host application when an iframe has failed to load.  Because of security sandboxing, the host isn’t allowed to know the HTTP status of the request or to inspect what was loaded, so we have to rely on waiting for a postMessage event from within the iframe to know it has successfully loaded

<MyMFE> <Route path="/mainContent"> <MyMainContent /> </Route> <Route path="/plugin1"> <Plugin fallbackComponent={<OtherFallback />}> <MyCustomContent /> </Plugin> </Route> </MyMFE>