Skip to content

feat: implements helper classes for configuring frontend plugin slots - #281

Closed
tecoholic wants to merge 3 commits into
overhangio:mainfrom
tecoholic:frontend-plugin-patch-helper
Closed

feat: implements helper classes for configuring frontend plugin slots#281
tecoholic wants to merge 3 commits into
overhangio:mainfrom
tecoholic:frontend-plugin-patch-helper

Conversation

@tecoholic

@tecoholic tecoholic commented Jan 12, 2026

Copy link
Copy Markdown

Description

This PR implements a set of helpful classes that make adding frontend plugins to MFEs easier and more declerative.

The main goal is to reduce the work for developers. The FrontendPlugin class rolls multiple patches into a simple declaration and removes the need to create env.config.jsx and module.config.js files in your MFE folder and having to run the dev server separately outside Tutor.

Compare the examples below:

Native patches

from tutormfe.hooks import PLUGIN_SLOTS
from tutor import hooks

hooks.Filters.ENV_PATCHES.add_item(
    (
        "mfe-dockerfile-post-npm-install-authoring",
        """
RUN npm install @tecoholic/frontend-plugin-lti-provider
""",
    )
)

hooks.Filters.ENV_PATCHES.add_item(
    (
        "mfe-env-config-buildtime-imports",
        """
import { AuthoringUnitPageSidebarWidget } from '@tecoholic/frontend-plugin-lti-provider';
""",
    )
)

PLUGIN_SLOTS.add_items(
    [
        (
            "authoring",
            "org.openedx.frontend.authoring.course_unit_sidebar.v2",
            """
            {
              op: PLUGIN_OPERATIONS.Insert,
              widget: {
                priority: 60,
                id: 'lti-provider-widget',
                type: DIRECT_PLUGIN,
                RenderWidget: AuthoringUnitPageSidebarWidget
              }
            }""",
        ),
    ]
)

Helper class

from tutormfe.helpers import FrontendPlugin, SlotConfig

FrontendPlugin(
    package="@tecoholic/frontend-plugin-lti-provider",
    local_path="/home/tecoholic/code/frontend-plugin-lti-provider",
    slots=[
        SlotConfig(
            mfe="authoring",
            slot_id="org.openedx.frontend.authoring.course_unit_sidebar.v2",
            component="AuthoringUnitPageSidebarWidget",
            priority=60
        ),
    ]
).register()

The helper classes remove a lot of boiler plate.

Development Workflow

  1. Add the MFE you are working on as a Tutor mount. (This is required for the MFE to run in dev mode)
  2. Add the frontend plugin you are developing as a Tutor mount. Eg., tutor mounts add authoring:/path/to/my-plugin:/plugins/my-plugin.
  3. Create a Tutor plugin configuration using the FrontendPlugin class as shown above. Make sure to include the local_path for development.
  4. Enable the plugin and start the MFE container. Eg., tutor plugins enable <tutor-plugin>, tutor dev start authoring.
  5. OPTIONAL - if you frontend plugin has a build step start the builder in watch mode, so the changes you make in your code is live-generated.

With this you should see the plugin loaded into the MFE and changes reflects in a hot-reload.

Related information

@tecoholic
tecoholic force-pushed the frontend-plugin-patch-helper branch from 83f1604 to 68eac9d Compare January 20, 2026 01:36
@tecoholic
tecoholic marked this pull request as ready for review January 21, 2026 01:50
@tecoholic

tecoholic commented Jan 21, 2026

Copy link
Copy Markdown
Author

@arbrandes After spending an unfair amount of time trying out different ideas, I think I finally have a working solution. It's rough around the edges code quality and testing wise (I have only tested one MFE and plugin combo). I have tried my best to not touch the existing functionality to keep everything backward compatible. It would be great to get some feedback before I spent anytime polishing this.

P.S: package_url support is not implemented yet.

@arbrandes

Copy link
Copy Markdown
Collaborator

@tecoholic, this is in my queue to review. I hope to get to it in the beginning of next week. If it looks good, I'll check with the other maintainers as well.

@tecoholic

Copy link
Copy Markdown
Author

@arbrandes Hi, it's been a while. Checking to see if you had chance to go through this PR.

@arbrandes

Copy link
Copy Markdown
Collaborator

@tecoholic, haven't forgotten about you. As a matter of fact, we're just now considering whether/how to follow this approach in frontend-base land. I'll come back here once we can think of a way that works for both types of MFEs.

@arbrandes

Copy link
Copy Markdown
Collaborator

Now that frontend-base support has landed in main, I think we should focus our attention on it. It's where the frontend is going - we shouldn't add new features to the legacy, at this point.

So... let's discuss this. This is what adding a frontend app (which is what a plugin is called in frontend-base land) looks like now. From the README:

from tutormfe.hooks import FRONTEND_APPS

from tutor import hooks

@FRONTEND_APPS.add()
def _add_my_app(apps):
    apps["my-app"] = {
        "npm_package": "@myorg/frontend-app-my-app",
        "npm_version": "^1.0.0",
        "enabled": True,
    }
    return apps

hooks.Filters.ENV_PATCHES.add_items(
    [
        (
            "mfe-site-config-imports",
            """
import { myApp } from '@myorg/frontend-app-my-app';
"""
        ),
        (
            "mfe-site-config",
            """
addApp(siteConfig, myApp);
"""
        ),
    ]
)

That's it. No slots to configure: that logic is now part of the app itself. (You can still configure slots individually if you want to a single-py-file plugin, but I would not recommend duplicating the upstream slot configuration logic because of that simple use-case.)

The question is whether it's worth the trouble of adding to the API surface area to go from the above to this:

from tutormfe.helpers import FrontendApp

FrontendApp(
    npm_package="@tecoholic/frontend-app-lti-provider",
    npm_version="1.0.0-alpha || 0.0.0-dev",
    components=["ltiProviderApp"],
).register()

What do you think?

@arbrandes
arbrandes marked this pull request as draft April 27, 2026 15:02
@arbrandes
arbrandes removed their request for review April 27, 2026 15:03

@arbrandes arbrandes left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(placeholder review)

@tecoholic

Copy link
Copy Markdown
Author

@arbrandes Hi, this is great. The frontend-base way of it feels truer to the micro frontend name than our current version of multiple React apps.

I didn't read through the full diff, but things like the following really stood out as good improvements in both architecture and DevX

  • For plugin authors: frontend apps are plugins themselves; the same API can be used to create Tutor plugins, including ones that add entire new routes.

Enabling or disabling existing apps does not require rebuilding tutor-mfe images: after a tutor config save, only a Tutor restart is required.

source accepts two shapes:

  • A git URL (https://..., git@...) - cloned at build time
  • A file:// URL (e.g. file://site/packages/frontend-app-my-app) - the path, relative to the tutor-mfe build context

With that I agree that this PR is no longer relevant for the future of tutor-mfe or that I would consider a similar API to be a big improvement in DevX, as the plugin config like priority, slot id..etc., are completely gone. Typing what should be validated JS code into triple-quote strings with no validation was one of the main drivers for me to embark on this alternate API. with that gone, I see less value. So, I am closing this PR.

Thank you for keeping this in mind and coming back to it. Cheers.

@tecoholic tecoholic closed this May 1, 2026
@ahmed-arb ahmed-arb moved this from Pending Triage to Won't fix in Tutor project management May 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Won't fix

Development

Successfully merging this pull request may close these issues.

4 participants