feat: add frontend-base support#285
Conversation
9f50915 to
431a4da
Compare
ff73920 to
767fd11
Compare
| "authn": { | ||
| "npm_package": "@openedx/frontend-app-authn", | ||
| "npm_version": "^1.0.0-alpha || 0.0.0-dev", | ||
| "enabled": True, |
There was a problem hiding this comment.
It is the consensus in Axim engineering that these should not be enabled by default for Verawood, primarily because users would have to engage with two different slot configuration APIs: one for Authn and Learner Dash, and another for all the other MFEs.
To get some usage data, we should instead:
- Try to publicize how easy it is to enable these two apps on and test "the future"
- Since this PR is expected to land, we can try to add some frontend-base testing to the Verawood testing plan, which should be made possible if we provide a sandbox.
|
Upstream blockers have landed, so this is now ready for review. |
| {%- endif %} | ||
|
|
||
| {% if mfe_data.unmounted|length > 0 or MFE_HOST_EXTRA_FILES %} | ||
| {% if mfe_data.unmounted|length > 0 or not site_mounts or MFE_HOST_EXTRA_FILES %} |
There was a problem hiding this comment.
Curious about this logic. I think the main thing that is making it seem confusing to me is that site_mounts (plural) implies we might have multiple sites. In the case where multiple sites exist, one is mounted and one isn't, then site_mounts would be truthy.
I see 2 possible solutions here:
- Rename
get_site_mountsandsite_mountstoget_site_mountandsite_mountrespectively. That would clarify the limitation of "we only support one site." - Support multiple sites. One possible way to do this would be to follow the
MFEMountDataclass pattern for aSiteMountDataclass.
There was a problem hiding this comment.
site_mounts (plural) implies we might have multiple sites
Not necessarily, if you take it to mean: "all of the site-related mounts that go into the mfe-dev service". This includes both the site itself, and/or the apps. So the name is fine, I think.
On the suggestions:
- Doesn't work, because there are really multiple mounts possible.
- That is explicitly a non-goal of this implementation: there is no scenario I can imagine where multiple sites is a desirable tutor-mfe feature. Users can already override the full site config if they want - I can see why somebody would want to do that - but multiple sites negates most (or at least, many) of the benefits of frontend-base.
There was a problem hiding this comment.
Gotcha. So with
if is_frontend_app_enabled(app_name):
mounts.append(("mfe", f"frontend-app-{app_name}-src"))
mounts.append(("mfe-dev", f"frontend-app-{app_name}-src"))the frontend-app-* mounts are "site mounts."
Seems like a classic "names are hard" problem. When I first saw get_site_mounts I read it as "get mounts for all the sites" instead of "get all the mounts for the one site."
There was a problem hiding this comment.
I'm actually looking into what we can do, here. Be back in a bit. :)
There was a problem hiding this comment.
Ok, I don't have a better idea for the name (what I commented earlier holds), but you did help clarify the implementation:
be78f2a to
7c8fbca
Compare
|
@ahmed-arb, I added a package-lock, as well as tooling to make updating it easier. And because Renovate cannot be used (because package.json is a Jinja template), I added a (daily?) Github workflow to do the job. |
a7fa1d3 to
9a9c263
Compare
|
This is blocked on openedx/frontend-base#227. Until then, the build fails: |
ad41a93 to
0aea6c7
Compare
|
We're unblocked: openedx/frontend-base#227 has merged. |
536187f to
fb0b623
Compare
There was a problem hiding this comment.
Overall this workflow makes sense to me, but I'm slightly concerned that it won't catch build failures with the updated lockfile.
I know in theory things should stay compatible with our pinning strategy, but I've run into issues where dependencies unintentionally release a breaking change as minor (most recently openedx/paragon#4218 / openedx/paragon#4257)
With renovate PRs this gets caught by CI, but I don't see anything in .github/workflows/test.yml or the test target in the Makefile that would catch things like that.
There was a problem hiding this comment.
Agreed, but the problem is that tutor mfe has never run CI against the actual build, probably because it's too expensive. Probably good for a follow-up conversation with the other maintainers.
There was a problem hiding this comment.
(Or it's just that this already runs as part of the Docker build process somewhere else not visible from here - which I think is the likely answer.)
fb0b623 to
1e35f74
Compare
| {%- if MFE_SITE_REPOSITORY %} | ||
| ADD --keep-git-dir=true {{ MFE_SITE_REPOSITORY }}#{{ MFE_SITE_VERSION }} . | ||
| {%- else %} |
There was a problem hiding this comment.
can we add MFE_SITE_VERSION in if condition as well.
There was a problem hiding this comment.
Good catch. Addressed!
| {%- for app_name, app in iter_frontend_apps() %} | ||
| {%- if app.get("npm_package") %} | ||
| "{{ app['npm_package'] }}"{{ "," if not loop.last }} | ||
| {%- endif %} | ||
| {%- endfor %} |
There was a problem hiding this comment.
This might break if loop.last does not have a npm_package. The second-to-last app that had the npm package will have a trailing comma, will result in invalid JSON.
There was a problem hiding this comment.
Good catch. This loop was not only dumb, it was wrong (it was missing frontend-base itself). Fixed.
Introduces a new build path for @openedx/frontend-base apps using npm workspaces. A default "frontend-site" is added alongside the existing MFE build, with its own multi-stage Dockerfile, Caddy routing, and site config files for both dev and production environments. Co-Authored-By: javier ontiveros <javier.ontiveros@wgu.edu> Co-Authored-By: Claude <noreply@anthropic.com>
17986f9 to
a371745
Compare
Description
Parent issue: openedx/frontend-base#133
Sandbox: https://frontend-base.openedx.io/
This PR adds support for frontend-base, a unified framework that replaces
frontend-build,frontend-platform,frontend-plugin-framework,frontend-component-header, andfrontend-component-footer. It enables frontend apps to be loaded as direct plugins within a single shell application, rather than as separate, independently deployed SPAs.When frontend apps are configured, the plugin builds a frontend-base site that bundles them together into this shell. The site is served by the same
mfecontainer alongside legacy MFEs, with Caddy routing requests appropriately.Four frontend apps are shipped here. Two new ones, enabled by default:
instructor-dashboardandnotifications. And two replacements for legacy MFEs:authn,learner-dashboard. These two are disabled by default. (Because we want to enable all new-style apps at the same time once all MFEs are converted, to minimize operator friction.)Implementation
The build infrastructure uses an npm workspaces monorepo with some usual suspects in the Dockerfile (
site-common,site-prod,mfe-dev). Frontend apps not configured to be pulled from NPM (such as when using a git repository or mounted for development) are installed and built as workspace packages. If one matches a legacy MFE, both are still built so that enabling/disabling apps can be done without an image rebuild, but the legacy MFE is effectively disabled for the end user.Runtime configuration is fetched from the LMS at
/api/frontend_site_config/v1/, populated from a newFRONTEND_SITE_CONFIGdictionary in the LMS settings. For backward compatibility, the endpoint also converts existingMFE_CONFIGandMFE_CONFIG_OVERRIDESto frontend-base's SiteConfig structure, at a lower precedence.In dev mode, mounting a
frontend-sitedirectory or anyfrontend-app-*repository starts a singlemfe-devservice for all apps, with hot-reload support. If the appropriatetutor mount adds are run, individual frontend app repos are bind-mounted as npm workspace packages into both themfeandmfe-devcontainers.Frontend apps (
FRONTEND_APPS) are introduced as a new hook alongside the existingMFE_APPS, with corresponding template helpers, LMS settings patches, and a full set ofmfe-site-*template patches for customization.New Tutor configuration variables:
MFE_SITE_PORT,MFE_SITE_REPOSITORY, andMFE_SITE_VERSION.Upstream blockers
Testing
This PR requires an up-to-date deployment of tutor@main (in particular, you'll need openedx/openedx-platform@57914c5 or newer). Make sure your Tutor installation is current before proceeding.
Install this PR's version of tutor-mfe:
Then save the configuration and rebuild images. Because the
mfeandmfe-devimages both need rebuilding, atutor dev launchis recommended:Baseline: legacy MFEs should still work. With authn and learner-dashboard disabled (the default), everything should behave exactly as before. All previous existing MFEs should load and function normally, including in development mode. There should be no detectable changes in behavior.
Enabling frontend apps. Next, enable the two core frontend apps that ship disabled (instructor-dashboard and notifications are enabled by default, already). Create a Tutor plugin (e.g.
"$(tutor plugins printroot)/enable_frontend_apps.py") with the following content:Then enable the plugin and restart (no image rebuild needed):
The frontend-base apps should then be accessible in the browser after being redirected from
http://local.openedx.io:8000tohttp://apps.local.openedx.io:8080. If you're logged in, you should be taken to the dashboard directly athttp://apps.local.openedx.io:8080/learner-dashboard/. If not, you should be taken tohttp://apps.local.openedx.io:8080/authn/login.Note: While the focus of this PR is on the frontend-base integration infrastructure, not on the functionality of Authn or Learner Dashboard themselves, any bugs encountered in those apps should still be noted.
Development modes. Try mounting individual frontend app repositories and also the whole frontend site for development. Note the behavior difference depending on whether a given app is enabled: when an app is enabled, mounting it provides hot-reload development of that app within the frontend-base site; when it is not enabled, mounting it starts it as a standalone MFE instead (the legacy behavior). See the "Frontend-base site development" section of the README for details.
TODO
LLM usage notice
Built with assistance from Claude.