Frontend Pluggability Summit, Part 1 (2023-10-25)

Purpose

The purpose of this page is to collect information that is relevant to the Frontend Pluggability Summit.

That summit will endeavor to a solve the following architectural problem.

  • Support customization of the platform’s frontend components, in support of the needs of independent users, without altering the shared foundation.

  • Provide that support in a way that minimizes – eliminates? – forking and minimizes extra effort to upgrade the platform and the carrying cost of customizations.

Requirements

customizations often extend beyond simply adding new features, they involve modifying existing features and components to align with specific business requirements. Also, one of the key considerations for us is maintaining the system’s upgradeability, we want to be able to easily transfer and apply platform customizations to the newer named releases, as they are ready. The current approach, which involves forking and customizing micro-frontends, makes this incredibly challenging.

Approach Brainstorming

Proposal

Proposer

Notes

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

 

 

 

 

  • Creating a UI Plugin Framework in React

 

Pluggability Use Cases

 

Actor

Use Case

Proposed By

Notes

Actor

Use Case

Proposed By

Notes

Deployers

almost every customer wants to modify the footer content (often also the header)

eduNEXT

 

Deployers

online academies (gathering from our saas offering) very often ask us to add additional fields to the Authn registration page.

eduNEXT

 

Deployers

online academies offering need to present the same additional fields from the Authn registration to the account settings page.

eduNEXT

Isn’t there already a basic mechanism for doing this? How does it fall short?

Deployers

University of Michigan wants to make redirections from the learner dashboard to a custom policy acknowledgment/acceptance page. (published in the issues of the mfe)

eduNEXT

 

Deployers

Spanish universities want add more filtering options to the course emails page (frontend-app-communications)

eduNEXT

I’m not sure what this means. Is there a reason why their choices wouldn’t be desirable by everyone using the app?

Deployers

Spanish universities authors want to add more buttons to the html editor (tinyMCE) to make iframe and other embeddings easier.

eduNEXT

 

Deployers

Spanish universities want to add an extra component to each block in the course content to gather feedback on the quality of the component.

eduNEXT

This feature feels like a cross between something that should be core, but currently is not and the ability to extend the platform. Perhaps the mechanism for plugging a feedback mechanism into every block should exist. Perhaps this should just be a platform feature.

Deployers

Pearson uses a side navbar block that want to add to the learning MFE so learners have easy access to the course navigation tree.

eduNEXT

 

Deployers

Organizations would like to add custom tools to courses and have both the tool and it’s configuration be installed optionally.

@Braden MacDonald

This use case is captured based on Braden’s work to demonstrate his plugin proposal.

Developers

As a developer I want to package a modern frontend with customizations to the Open edX platform backend.

@Edward Zarecor

@Glib Glugovskiy capturing this in relation to the work you are doing to redesign the video block to use a React-based front end.

Deployers

As a deployer, I want to be able to hide items from frontend views that are not relevant to my deployment. Some examples from the Learner MFE:

  • Related Programs

  • Recommendations for You

  • Upgrade

  • Grade Required to Pass the Course

  • Social Media Buttons

@Edward Zarecor

Summarizing a request that came from @Meredith Davies at MIT.

 

“Learning Assistant”

 

https://github.com/edx/frontend-lib-learning-assistant

 

Zendesk

 

https://github.com/openedx/frontend-app-learner-dashboard/tree/master/src/components/ZendeskFab

Developers

As a developer, I want to only deploy and maintain the frontend plugin that my team has ownership of, while another team/developer is responsible for the Host MFE they have ownership of.

@Jason Wesson

 

Developers

As a developer, I want to be able to replace any default content (main branch content) of a host MFE with my frontend plugin.

@Jason Wesson

 

Proposed Schedule

In advance, asynchronously:

  • Discuss and catalog the requirements for frontend pluggability in this thread

  • Capture any prior art either from the Open edX project or other platforms

  • Propose high level approaches and build teams around them to create a high level approach document. This is really like an asynchronous design hackathon, pitch an idea, build a team, produce an artifact.

  • Publish and review the proposed approaches

At the summit, synchronously:

  • Spend some time reviewing and discussing the requirements.

  • Review and discuss proposals that are on the table

  • Discuss the pros and cons of all approaches as a group over the course of several synchronous hours

  • Converge on a plan that will become an ADR or OEP documenting the approach

  • Develop a specific plan to deliver this capability where all stakeholders contribute to completing the work.

After the meeting, asynchronously:

  • Do the work to publish the architectural decision

  • Do a technical spike/POC to validate the selected technical approach

  • Groom the required work, determine who will do which parts, execute and ship it.

Agenda for 10/25 Summit

  • Requirements/Problem Space Review

  • Candidate Solution Presentations (15 minutes each)

    • @Braden MacDonald

    • @Jason Wesson

    • @Glib Glugovskiy

    • @Adolfo Brandes

    • ?

  • Solution Review

    • Discuss how each solution meets or misses key requirements

    • Discuss relevant non-functional requirements, e.g., maintainability, flexibility, understandability.

    • Can we agree on a clear best choice?

  • Plan Development and Next Steps

Proposed Evaluation Rubric for Discussion

Attribute

Poor

Decent

Solid

Maintainability

Requires maintaining a substantial fork

Better with notable flaws

Requires only Installing and enabling custom plugins

Upgradability (may be a subset of the above)

Each plugin must be manually verified between releases

Some verification required between releases, but it’s easy to find what changes are required

Stable API - plugin authors need not touch plugins between releases

Flexibility

Restrictive, fixed options.  Easy to hide things, but hard to add or change existing things

Better with notable flaws

High degree of control.  Can add, update and delete components

Approachability

Off the beaten track, surprising, steep ramp

Better with notable flaws

Simple and familiar patterns, reasonably easy to grok, few surprises.

Security

Introduces new attack vectors.

Better with notable flaws

Meets our existing security patterns and requirements

Performance

Significant performance tradeoffs, difficult to cache, large apps, poor sharing of libraries

Better with notable flaws

Optimized app sizes, maximal sharing of libraries, high-level of cachability at edge and client.

Accessibility

Hard to implement our standards for a11y, i18n, and l11n.

Better with notable flaws

Standards achieved via existing patterns

Operability

Must release to change any component.  Customizations are statically delivered

Better with notable flaws

Individual components are independently updatable.  Runtime configuration is available.  Split tests are possible.

Participants

  • @Edward Zarecor

  • @Kristin Aoki

  • Arslan

  • @Jhon Venté

  • @Maria Grimaldi

  • @Jason Wesson

  • @Kelly Buchanan

  • @Glib Glugovskiy

  • @Ghassan Maslamani

  • @Jeremy Ristau

  • @Max Frank

  • @Dave Ormsbee (Deactivated)

  • @Stefania Trabucchi

  • @Brian Smith

  • @Marlon Keating

  • @Braden MacDonald

  • Raza

  • @George Babey

  • @Ben Warzeski (Deactivated)

  • Vahid (Edspirit)

  • @Adolfo Brandes