Problems applying Customised MFE libraries (eg "frontend-platform") to a production Open edX platform (using "tutor local")

Dear all,

I think I finally managed to find a solution that is also acceptable from tutor perspective. I’ll give a complete rundown here, so if someone else is facing the same issue, you should be able to follow the guide.

** Note that all changes described here must be repeated for each new release!** For the sake of an example, we’ll be modifying the most recent olive.2 release.

Background information

Some very high level information. MFEs are essentially standalone and independent ReactJS applications which communicate using the OpenEDX API with the main application stack. They all leverage common modules (like frontend-platform for example), but those are just regular npm dependencies.

When starting a Tutor environment, the tutor-mfe plugin is responsible for managing the MFEs. On a very high level, without going too much into detail, the plugin builds a Dockerfile based on a template and the plugin configuration, and this Dockerfile is then used to build the mfe container.

There is one single container (mfe) which hosts all MFEs. When the container is built, the Dockerfile contains various steps for each MFE, like clone the source code, apply some i18n changes, do npm install and build. That means the container essentially just serves static assets (the compiled react application).

Now the general idea to add additional languages is to create a fork of each MFE repository we’re interested in and make sure those repos are used to build the new MFE container.

This next section just describes the changes you need to do, the second section focusses on how to do them.

Required Changes

In general, there’s two changes that need to be done:

  • Custom translation needs to be added to each MFE you’re interested in
  • Language need to be added to the dropdown in the account MFE so users can actually choose

To add your language to the dropdown on the account page, you’ll need to modify src/account-settings/site-language/constants.js in frontend-app-account:

index 6854958..efea6e0 100644
--- a/src/account-settings/site-language/constants.js
+++ b/src/account-settings/site-language/constants.js
@@ -14,6 +14,11 @@ const siteLanguageList = [
     name: 'Català',
     released: false,
+  {
+    code: 'de-de',
+    name: 'Deutsch',
+    released: true,
+  },
     code: 'es-419',
     name: 'Español (Latinoamérica)',

Second, to add your language to the MFE, the following steps need to be done (its the same for each MFE, so you need to apply these changes to each MFE):

Update src/i18n/index.js to include your language, in this example, German has been added:

index 8a01428..b762993 100644
--- a/src/i18n/index.js
+++ b/src/i18n/index.js
@@ -1,6 +1,7 @@
 import arMessages from './messages/ar.json';
 import caMessages from './messages/ca.json';
 // no need to import en messages-- they are in the defaultMessage field
+import dedeMessages from './messages/de_DE.json';
 import es419Messages from './messages/es_419.json';
 import frMessages from './messages/fr.json';
 import zhcnMessages from './messages/zh_CN.json';
@@ -15,6 +16,7 @@ import ukMessages from './messages/uk.json';
 const messages = {
   ar: arMessages,
+  'de-de': deMessages,
   'es-419': es419Messages,
   fr: frMessages,
   'zh-cn': zhcnMessages,

Next, fetch your language file from Transifex (if it exists), you need a JSON file. Some common transifex repositories:

Once you’ve located the transifex project you’re interested in, click on your language and click on Download for use. This should give you a JSON file. Rename this file according to the import in index.js and place it in i18n/messages/ (in our example, this would be i18n/messages/de_DE.json).

Apply changes

To apply these changes, perform the following steps for each MFE you want to modify

  • Fork the MFE (make sure not only to copy the master branch, you need everything)
  • Clone it to a local directory
  • Go to the official OpenEDX Repository for the MFE you’re modifying and find the commit hash associated to your release (8dbf20b in this example).

  • In your local clone, create a new branch off this commit: git branch your_org_olive.2 8dbf20b && git checkout your_org_olive.2
  • Make the changes described above
  • Next, we’ll commit all changes and move the release tag to the new version you’ve just created. Alternatively, you can use a custom tag and specify the version attribute for the MFE config later.
# Add all modified files
$ git add -A

# Commit all changes
$ git commit -m "your org specific olive.2 release"

# Delete existing release tag
$ git tag --delete open-release/olive.2

# Create a new release tag pointing to your new commit
$ git tag open-release/olive.2

# Alternatively, omit the previous two steps and simply create a new tag:
$ git tag your-org/olive.2

# Assumes origin is your remote
$ git push origin
$ git push origin --tags -f # Force (-f) is only needed if you changed the original release tag, as the tag still exists in the remote repository

Make Tutor use your new forks

The final step is to tell Tutor to use your new forks. To do this, modify your config.yml ( $(tutor config printroot)/config.yml) and add the following for each MFE:

  name: <mfe_name>
  port: <mfe_port>

# Example
  name: authn
  port: 1999

# Example with version
# Optionally, if you don't use the official release tag for your changes, you can do:
  name: authn
  port: 1999
  version: your-org/olive.2

Note that you can find the defaults (MFEs, ports and their Repositories) here. Note that you need to prefix the configuration variable names by the plugin name (MFE in this case).

Warning: While it might be tempting to simply change them in the Dockerfile ($(tutor config printroot)/env/plugins/mfe/build/mfe/Dockerfile), this is a bad idea as those URLs would be overwritten by the next tutor config save.

Last but not least, rebuild the MFE image and restart the container, picking up the new image:

$ tutor images build mfe
$ tutor local dc up -d mfe

I hope this helps someone.