Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,23 @@ See the fragment files in the [changelog.d/ directory](./changelog.d).

<!-- scriv-insert-here -->

<a id='changelog-22.0.0'></a>
## 22.0.0 — 2026-05-18

### Added

- Support to verawood release

* Extend BY_PATH hosting for **frontend-site apps** (e.g. `instructor-dashboard`)

* Route enabled frontend apps through LMS Caddy when `MFE_EXTENSIONS_BY_PATH` is on.

* Proxy frontend-site webpack assets served at the LMS domain root (`runtime.*.js`,
`*-main.*.js/css`) to the MFE container, fixing blank instructor dashboard pages.

* Set `INSTRUCTOR_MICROFRONTEND_URL`, `CATALOG_MICROFRONTEND_URL`, and LMS
`MFE_CONFIG` / `FRONTEND_SITE_CONFIG` base URLs for BY_PATH on the LMS host.

<a id='changelog-21.0.2'></a>
## 21.0.2 — 2026-05-14

Expand Down
7 changes: 4 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "tutor-contrib-mfe-extensions"
version = "21.0.2"
version = "22.0.0"
description = "mfe_extensions plugin for Tutor"
readme = "README.md"
requires-python = ">=3.10"
Expand All @@ -16,10 +16,11 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
]
dependencies = [
"tutor~=21.0",
"tutor-mfe~=21.0",
"tutor @ git+https://github.com/overhangio/tutor@59264ca9f9c6a8e67622ae72080684ffc6ec7e2a",
"tutor-mfe @ git+https://github.com/overhangio/tutor-mfe@d0804c2590431780d3a0ed6d24701c20eef5a86d",
]

[project.urls]
Expand Down
12 changes: 12 additions & 0 deletions tutormfe_extensions/patches/caddyfile-frontend-site-assets
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{%- if MFE_EXTENSIONS_BY_PATH and get_frontend_apps() %}
# Frontend-site bundles (e.g. runtime.*.js) are served from /openedx/dist/site at the
# MFE root. When hosting by path on the LMS domain, proxy those asset paths to mfe.
@mfe_frontend_site_assets {
path_regexp assets ^/(runtime|app|cssLayerOrder|[0-9]+|[a-z0-9-]+-main)\.[a-f0-9]+\.(js|css)$
}
handle @mfe_frontend_site_assets {
reverse_proxy mfe:8002 {
header_up Host {host}
}
}
{%- endif %}
Comment on lines +1 to +12

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would need to test it first, but at first glance I have some doubts about this configuration.

Correct me if I’m wrong, but after reviewing this issue overhangio/tutor-mfe#285

I don’t see anything that would require changing the behavior of the main Caddy to serve those assets. My understanding is that, even though the files are now served from /openedx/dist/site, they should still follow the same logic as before, so the request should continue reaching the MFE Caddyfile (mfe:8002), and that Caddyfile should handle looking for the files in the corresponding path.

Did you try mfe-extension without this change? If so, what error do you get?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

In legacy MFEs those assets live under /{app}/ and /instructor-dashboard/* → mfe:8002 is enough.

For frontend-site apps, webpack still emits root-level bundles (/runtime..js, /instructor-dashboard-main..js). I tested without this patch: HTML under /instructor-dashboard/ works, but /runtime.*.js returns 404 from the LMS (never hits mfe:8002). That matches a blank instructor dashboard. This patch only proxies those root asset paths to mfe:8002 when BY_PATH + frontend apps are enabled.

image

1 change: 1 addition & 0 deletions tutormfe_extensions/patches/caddyfile-lms
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
{{ patch("caddyfile-mfe-by-path") }}
{{ patch("caddyfile-frontend-site-assets") }}
15 changes: 13 additions & 2 deletions tutormfe_extensions/patches/openedx-lms-production-settings
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
{% if MFE_EXTENSIONS_BY_PATH %}
MFE_CONFIG["BASE_URL"] = "{% if ENABLE_HTTPS %}https{% else %}http{% endif %}://{{ LMS_HOST }}"
FRONTEND_SITE_CONFIG["baseUrl"] = "{% if ENABLE_HTTPS %}https{% else %}http{% endif %}://{{ LMS_HOST }}"

LEARNING_MICROFRONTEND_URL = "{% if ENABLE_HTTPS %}https{% else %}http{% endif %}://{{ LMS_HOST }}/learning"
MFE_CONFIG["LEARNING_BASE_URL"] = "{% if ENABLE_HTTPS %}https{% else %}http{% endif %}://{{ LMS_HOST }}/learning"

Expand All @@ -7,7 +10,7 @@ ADMIN_CONSOLE_MICROFRONTEND_URL = "{% if ENABLE_HTTPS %}https://{% else %}http:/
MFE_CONFIG["ADMIN_CONSOLE_URL"] = ADMIN_CONSOLE_MICROFRONTEND_URL
{% endif %}

{%- if get_mfe("authn") %}
{%- if get_mfe("authn") or is_frontend_app_enabled("authn") %}
AUTHN_MICROFRONTEND_URL = "{% if ENABLE_HTTPS %}https{% else %}http{% endif %}://{{ LMS_HOST }}/authn"
AUTHN_MICROFRONTEND_DOMAIN = "{{ LMS_HOST }}/authn"
{%- endif %}
Expand All @@ -26,7 +29,7 @@ MFE_CONFIG["DISCUSSIONS_MFE_BASE_URL"] = DISCUSSIONS_MICROFRONTEND_URL
WRITABLE_GRADEBOOK_URL = "{% if ENABLE_HTTPS %}https{% else %}http{% endif %}://{{ LMS_HOST }}/gradebook"
{% endif %}

{% if get_mfe("learner-dashboard") %}
{% if get_mfe("learner-dashboard") or is_frontend_app_enabled("learner-dashboard") %}
LEARNER_HOME_MICROFRONTEND_URL = "{% if ENABLE_HTTPS %}https{% else %}http{% endif %}://{{ LMS_HOST }}/learner-dashboard/"
{% endif %}

Expand All @@ -43,6 +46,14 @@ MFE_CONFIG["ACCOUNT_PROFILE_URL"] = "{% if ENABLE_HTTPS %}https{% else %}http{%
COMMUNICATIONS_MICROFRONTEND_URL = "{% if ENABLE_HTTPS %}https{% else %}http{% endif %}://{{ LMS_HOST }}/communications"
{% endif %}

{% if get_mfe("catalog") %}
CATALOG_MICROFRONTEND_URL = "{% if ENABLE_HTTPS %}https{% else %}http{% endif %}://{{ LMS_HOST }}/catalog"
{% endif %}

{% if is_frontend_app_enabled("instructor-dashboard") %}
INSTRUCTOR_MICROFRONTEND_URL = "{% if ENABLE_HTTPS %}https{% else %}http{% endif %}://{{ LMS_HOST }}/instructor-dashboard"
{% endif %}

{% if get_mfe("authoring") %}
MFE_CONFIG["COURSE_AUTHORING_MICROFRONTEND_URL"] = "{% if ENABLE_HTTPS %}https://{% else %}http://{% endif %}{{ LMS_HOST }}/authoring"
{% endif %}
Expand Down
15 changes: 14 additions & 1 deletion tutormfe_extensions/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from tutor import hooks
from tutor.types import Config
from tutormfe.hooks import MFE_APPS
from tutormfe.plugin import CORE_MFE_APPS
from tutormfe.plugin import CORE_MFE_APPS, get_frontend_apps, is_frontend_app_enabled

from .__about__ import __version__

Expand Down Expand Up @@ -72,17 +72,30 @@ def iter_mfes_per_service(service: str = "") -> Iterable[str]:
Return the list of MFEs that should be hosted via path in the
same domain as each service.

Includes legacy MFEs from MFE_APPS and frontend-base apps that are enabled
(e.g. instructor-dashboard), which are not registered in MFE_APPS.

"""
active_mfes = MFE_APPS.apply({})
cms_mfes = {"authoring"}
lms_mfes = set(CORE_MFE_APPS) - cms_mfes
seen: set[str] = set()

for mfe in active_mfes:
if service == "lms" and mfe in lms_mfes:
seen.add(mfe)
yield mfe
if service == "cms" and mfe in cms_mfes:
seen.add(mfe)
yield mfe

if service == "lms":
for app_name in get_frontend_apps():
if app_name in seen or app_name in cms_mfes:
continue
if is_frontend_app_enabled(app_name):
yield app_name


hooks.Filters.ENV_TEMPLATE_ROOTS.add_items(
[
Expand Down
16 changes: 7 additions & 9 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.