Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Proposal

Proposer

Notes

Create an Open edX specific UI Plugin Framework in React

Braden MacDonald

Designing and implementing the plugin framework was surprisingly easy, and it’s been working well ever since. I put the design details and code on my blog: Creating a UI Plugin Framework in React 3. If anyone has questions about what I learned from that experience, I’m happy to answer them. But the main point I’d like to make is that it doesn’t have to be complicated, and in my experience it can be done quickly and easily, even for relatively complex applications (I had to support white labelling, runtime config, plugin-defined URLs, theming via plugins, etc.).

In fact, if you end up with an approach like I took for that project, rolling it out at first is [almost] as simple as putting <DefaultUiSlot> ... </DefaultUiSlot> around the major elements of your user interface. Ta-da, it’s customization-ready.

Design an approach similar to Docosaurus’s Swizzling mechanism

Braden MacDonald

Another well-known approach to UI plugins is Swizzling 1, used by Docusaurus themes to customize their React UI. It has some overlap with my approach, but some major differences. The ways in which you can modify components are more limited, but you can modify virtually any component without having to declare it as a “slot”.

Extend a POC developed by David Joy (Deactivated) at 2U that provides iframe based “slots” for frontend customization

Jason Wesson

Frontend Plugin Framework

I’ll add that another existing PR that was started by @djoy and that I’m working to finish is for enabling a React-based iFrame plugin that lives in openedx/frontend-platform.

In terms of its abilities, it allows for:

  • Customizable window width/height of plugin slot

  • Multiple child MFEs can live inside a single plugin slot

  • Designed for future plugin types (LTI, Build-time, Module Federation) to be rendered based on the child MFE’s configuration. Linked is where the iFrame case exists and where the other types implementation logic would exist.

As for the PR, what’s left is:

  • Determine the desired fallback for when a plugin fails to render ADR

  • Write a test that ensures the desired fallback works correctly

Build-time module replacement using Webpacks’s NormalModuleReplacementPlugin

Glib Glugovskiy

We are currently exploring the use of NPM overrides and additional Webpack scripting. These could be integrated into the frontend-build repository without necessitating the forking of other frontend-app-* repositories.

Last month, we initiated an internal discovery with the following objectives:

  • Identify methods to override JavaScript code in Micro-Frontends (MFEs) with minimal changes, possibly by leveraging existing solutions in frontend-build or frontend-platform repositories.

  • Use a single repository to manage all code overrides and new customizations across MFEs.

  • Our customizations should be compatible with the latest MFE versions with minimal adjustments required.

  • Share a working example or even a fully implemented solution, specifically tailored for the Palm release MFEs.

We’ve developed a Proof of Concept (POC) using Webpack’s NormalModuleReplacementPlugin to replace entire files (modules) at build time. You can find it here: mfe-overrides GitHub Repository. We’ve tested this on a live installation, and it’s functional. However, it’s still a work in progress and requires further refinement to serve as a comprehensive solution.

Consider an approach similar to backstage’s

Edward Zarecor

I’m including for completeness. There are a number of things that I don’t like about how Backstage does plugins. For example, you need to directly alter source of platform pages to include plugins in base pages. However, they have optimized dev tooling to support a vibrant ecosystem of plugins.

https://john-tucker.medium.com/backstage-plugins-by-example-part-1-a4737e21d256

https://john-tucker.medium.com/backstage-plugins-by-example-part-2-6ead20cb4c8d

https://backstage.io/docs/plugins/create-a-plugin/

Leverage the Piral framework

Adolfo Brandes & Pedro Martello

Slides: https://docs.google.com/presentation/d/14ZkIqYnc5EOSPujxylSfi7W5eJWXaguD-3ECLlURoKA/edit

You may (or may not) have heard of Piral, and how we’re trying to leverage it for the Open edX frontend. And while Piral need not concern itself with in-page customization - this can be achieved completely independently of it - it does provide mechanisms that can be used to achieve pluggability as well.

Mechanism 1: Extensions

  • A central SPA loads “pilets” (UMD modules, to which MFEs can be easily converted to) at runtime; which pilets are loaded is up to an external feed service, which can be as simple as a json file on S3

  • Pilets can define “extension slots”, which can then be filled by “extensions” on other pilets

  • An operator can then set up their pilet feed to serve “extension pilets”, essentially a pilet for each desired plugin, or a pilet with many plugins - it’s up to the operator

Pros
  • Runtime loading of plugins: think different plugins for different tenants

  • No need to rebuild, no messing with package.json

  • No need to predict/preassign NPM package names: all a plugin needs to know is the extension slot name

Cons
  • No predefined concept of widgets or actions (though it could probably be done)

  • Piral must be adopted and MFEs converted to pilets

  • We’d start depending on Piral for more than just MFE composition

Mechanism 2: Events

Piral provides a simple but flexible event system. It would be a simple matter for custom MFEs/pilets/extensions to listen to and react to known events emitted by any other MFE/pilet/extension.

Pros
  • openedx-events for the frontend! (Open question: would filters be possible?)

Cons
  • Piral dependency

...