Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Apps, routes, and slots (openedx#2)
This PR significantly re-imagines the module, header, footer, and plugin configuration in frontend-base. The system is now focused around routes and slots. Slots are in the style of frontend-plugin-framework, tweaked to work with the lessons learned by rebuilding the header and footer, along with the needs of loading 'apps' representing the functionality of today's MFEs. Site Config The SiteConfig has a few new data structures: apps: This section includes 'app' configurations with routes, slots operations, and i18n messages. federatedApps: This section contains configurations for module federation, including "hints", a new concept that allows the shell to delay loading a federated module until it's needed by the site. A hint can be a route prefix or a slot identifier. remotes: The configuration for the remotes needed by our federatedApps. externalRoutes: A list of external URLs associated with semantically meaningful 'roles', allowing the system to seamlessly navigate to external pages without needing to know they're not part of the site, meaning they could be added in later without any of the apps needing to know about it. Apps Each App in apps can include a slots data structure that describes operations that App wants to perform on slots anywhere in the site. An app can add widgets to a slot, change the slot's layout, or supply 'options' to the layout to change it's configuration. Notably, layouts do not pass any props to widgets. A widget is a component without props. To use a React component that takes props as a widget, it can be wrapped in another component that supplies the props. The slot can provide a React Context to share contextual data with its widget children. The slot operations also allow overriding the layout, supplying it options (layout-specific config), or modifying an existing widget. This is a test. The goal is for widget overrides, layout options, and layout overrides to supply all the configuration we need, rather than having to reason through complicated props merging between slots and their children. It may not work, in which case we'll try to carefully layer in prop overrides for layouts/widgets as well. Routes After thinking it through for quite a while, I reached the conclusion that routes and slots are effectively two separate things. React-router's configuration gives us everything we need to have a comprehensive route rendering system, trying to insert our slots into the middle of it only makes it more complicated for very little benefit. A slot's layout or widgets can use a React Router Outlet component to indicate that it's a place where a given route should be rendered. A layout may also use its widgets to display visual metadata about the routes it's responsible for rendering. For instance, a tabbed container component could use its widgets to display the tabs, and an Outlet for the main content of the container. The tabs would be links to the proper routes, and react-router will just do the right thing with the Outlet. Module Federation Module federation can occur at two levels. First, at the "FederatedApp" level. FederatedApps are included in the federatedApps data structure, and the site uses their hints to know when to load their App config (their routes, slots, and messages). Once a remote App has been loaded, it's added to the apps array and acts like any other app. The other way to use module federation is in a slot. This is useful for Apps that want to load resources from other remotes. There's a special slot operation for loading a widget via module federation, where a remoteID and moduleID are supplied instead of a React element or component. The slot will use Suspense to load the module on demand when the slot is rendered. Commits: * feat: reimagining of shell config as slots This commit is one of several significantly refactoring the shell, header, footer, menu helpers, and site config into a system with frontend-plugin-framework-style “Slots” as a central concept. An “App” consists of a set of routes, slot configurations, and i18n messages. Routes are react-router routes, and are generally unrelated to slots. Slots are configured via operations. The only type of slot right now is a “widget” slot, which renders UI components into a ‘layout’ container. There are operations to work with widgets and the parent slot layout. Subsequent commits will add new versions of the header/footer and menu helpers. It will then use them all in the dev-project and test-project. * feat: simplifies shell ‘menu’ helpers This commit clears out a bunch of helpers for creating menus in the header and footer, simplifying them into a reusable component that’s aware of widget and route roles and can render itself as various link-like components. Subsequent commits to the header/footer sub-folders will use this (and the previous ‘slot’ commit) extensively. * feat: re-working Header to use slots This commit reworks the default header component to use slots for all its children. It supplies a default header app which makes use of all the slots in a way that should be a good starting point for most operators. * feat: refactor the footer to use slots Like the previous commit did for the header, this commit refactors the footer to use slots for configuration. * test: Refactor the ‘dev-project’ to use the new app/slot system This refactors site.config.dev.shell and the sample pages in dev-project to use the new system. The ‘home’ and ‘user’ apps in dev-project export App configurations with routes and slots to test out the various features of the new system. * fix: removing unused slot operation types We’ll add these back in once they’re actually usable.
- Loading branch information