diff --git a/README.rst b/README.rst index 18bb1c04..77458375 100644 --- a/README.rst +++ b/README.rst @@ -308,6 +308,120 @@ In case you need to run additional instructions just before the build step you c You can find more patches in the `patch catalog <#template-patch-catalog>`_ below. +Using Frontend Plugin Slots +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``mfe-dockerfile-pre-npm-build`` patch is also suitable for taking advantage of the ``env.config.jsx`` mechanism, which lets you define and use frontend plugins. For instance, you can use it to modify the footer across all MFEs without having to fork ``frontend-component-footer``. + +You can start by following the Tutor plugin tutorial at the `Adding new templates `_ section, though instead of adding a whole new Dockerfile, you'll just modify the exiting one. Your ``myplugin.py`` should look something like this: + +.. code-block:: python + + import os + from tutor import hooks + + # Add the template root folder + template_folder = os.path.join(os.path.dirname(__file__), "templates") + hooks.Filters.ENV_TEMPLATE_ROOTS.add_item(template_folder) + + # env.config.jsx files should live in `mfe/build/mfe`, which is also where the + # tutor-mfe Dockerfile goes. This is so it's more straightforward to copy it + # in, as seen below. + hooks.Filters.ENV_TEMPLATE_TARGETS.add_item(("mfe/build/mfe", "plugins")) + + # This patch gets inserted into the tutor-mfe Dockerfile. It copies our + # env.config.jsx into the root of each and every MFE before the npm build step. + hooks.Filters.ENV_PATCHES.add_item(("mfe-dockerfile-pre-npm-build", + "COPY env.config.jsx /openedx/app" + )) + +As for ``env.config.jsx``, as noted above, it should be put into a ``templates/mfe/build/mfe`` subdirectory below ``myplugin.py``. This is so it's easy to ``COPY`` it into the Docker image. In order for the file to work with all current MFEs, this is what it should look like: + +.. code-block:: javascript + + /* We can't just assume FPF exists, as it's not declared as a dependency in all + * MFEs. Therefore, we have to use dynamic imports to check if it's available. + * + * We also have to use a `try` block (as opposed to `.then()`), otherwise + * Webpack won't treat the import as optional. Hence the async function. + */ + async function getConfig () { + let config = {}; + + try { + const { DIRECT_PLUGIN, PLUGIN_OPERATIONS } = await import('@openedx/frontend-plugin-framework'); + + config = { + pluginSlots: { + footer_slot: { + plugins: [ + { + /* Hide the default footer. */ + op: PLUGIN_OPERATIONS.Hide, + widgetId: 'default_contents', + }, + { + /* Insert a custom footer. */ + op: PLUGIN_OPERATIONS.Insert, + widget: { + id: 'custom_footer', + type: DIRECT_PLUGIN, + RenderWidget: () => ( +

This is the footer.

+ ), + }, + }, + ] + } + } + }; + + /* NPM allows us to introspect the package name at build time, which in turn + * lets us tailor the configuration for individual MFEs. + */ + if (process.env.npm_package_name == '@edx/frontend-app-profile') { + config.pluginSlots.footer_slot.plugins[1].widget.RenderWidget = () => ( +

This is the profile MFE's footer.

+ ); + } + } catch { }; + + return config; + } + + export default getConfig; + +As you can see, by using the ``process.env.npm_package_name`` variable you can use a single ``env.config.jsx`` to selectively apply configuration to different MFEs. + +If, on the other hand, you prefer to maintain entirely separate ``env.config.jsx`` files, one for each mfe, that can also be done. For that you can rely on the ``mfe-dockerfile-pre-npm-build-*`` patch. For instance: + +.. code-block:: python + + hooks.Filters.ENV_PATCHES.add_items([ + ( + "mfe-dockerfile-pre-npm-build", + "COPY env.config.jsx /openedx/app" + ), + ( + "mfe-dockerfile-pre-npm-build-account", + "COPY env-account.config.jsx /openedx/app/env.config.jsx" + ), + ( + "mfe-dockerfile-pre-npm-build-profile", + "COPY env-profile.config.jsx /openedx/app/env.config.jsx" + ) + ]) + +In this case, there's a global ``env.config.jsx``, but it would get overwritten by the specific ones for the Account and Profile MFEs. Note that while they originally have different names, they should all still be copied to ``env.config.jsx``. + +You can find what slots a library or MFE supports by inspecting its ``src/plugin-slots`` directory on Github. For example: + +- `Header slots`_ +- `Learning MFE slots `_ +- `Learner dashboard MFE slots `_ + +For more information on how frontend plugin slots work, refer to the `Frontend Plugin Framework README `_. + Installing from a private npm registry ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~