FC 0007 - Piral and single-spa

Piral and single-spa are javascript libraries that support the development and deployment of front end client applications that use the micro front end (MFE) pattern. They differ significantly in their approach.

single-spa is a low level library that addresses 3 chief concerns - managing a lifecycle for MFE applications, managing a top level DOM container for hosting MFEs, routing between the MFE applications. There are community supported libraries and recommended setups to address higher level features and services and some are reviewed below. Server side rendering is supported in single-spa and there are helpers for fetching, composing, rendering and hydrating the MFE clients.

In single-spa the container application (Root-config) is a plain javascript application that uses the single-spa API to manage MFEs. MFEs (applications) can be developed in any javascript framework and are responsible for their own layout, backend interactions, and interactions with other MFEs. They are architecturally independent of the single-spa root-config that they are deployed in. MFE’s must export 3 required and 1 optional lifecycle method that the root-config uses to manage their lifecycle. single-spa provides MFEs with an API for managing a global event handler, discovering other MFEs, and other read interactions with the container.

The low level requirements for creating a single-spa compliant MFE means it can easily be integrated into an existing MFE ecosystem like open edX. Existing MFE’s would have to implement and export the required lifecycle methods as part of a conversion effort. But further changes to the MFEs could be easily very limited in scope and introduced gradually as part of major architecture sprints or epics. One drawback of such an approach is that while it sets a foundation for more coordination between MFEs and the container, it does very little to actually address the major requirements expressed in the open edX proposal vis-a-vis consistency in the design and implementation of MFEs, consistency in the user experience, reduction in the number of redundant changes that need to be made.

The single-spa community has proposed a recommended setup which addresses some additional architectural concerns such as dependency sharing via import maps, how to use “utility” MFEs for shared features and components and others. The community has additionally developed a number of solutions to further provide higher level features such as React or Angular and their respective layout capabilities. The value of each of these projects needs to be evaluated separately. It is worth noting that Qiankun is a single-spa derived framework that adds some of the higher level features such as shared global state, inter MFE messaging, resource loading and others. Such a framework adds very necessary features to single-spa to address the requirements that single-spa alone cannot help meet.

Piral is a higher level library that uses the React framework to provide a plugin architecture for loading micro front ends (pilets) into a Piral container (application shell). Server side rendering is supported in Piral and there are helpers for fetching, composing, rendering the MFE clients; hydration is handled natively by React. In addition to managing the lifecycle, top level layout and routing, Piral provides an extensive set of features and services to facilitate the development of pilets, including:

  • shared dependencies - eg: React, React-DOM and paragon;

  • global shared state

  • authentication and authorization plugins

  • shared high level components such as notifications, modals etc…

  • Global and intra MFE routing

  • Messaging between MFEs

  • global layout handling

In Piral the application shell is a React application and serves as a router and layout manager for MFEs, as well as a host for facilitating cross MFE interoperability, resource and dependency sharing, and a consistent user experience. After the application shell is created, it distributes a library that is used to create pilets. Each pilet will import all resources from the shell by simply declaring the exported library as a dependence. A Pilet must export a setup() method which is the only lifecycle method in Piral. The Piral API is injected in this setup method and it combines common and custom methods that allow pilets to interact with the shell and each other.

In contrast to single-spa, Piral offers a very opinionated view of how to address these architectural challenges and the initial implementation effort of converting existing open edX MFEs will be more complex in Piral in order to take advantage of the many higher level features that the platform offers. Implementation of some features can be deferred but some changes will be immediate such as use of shared dependencies, exploring advantages of using Piral with Paragon, use of Piral for routing, and authentication and layout among others.

While single-spa offers a much easier ramp into the managed micro front end ecosystem, the Piral framework does a lot more to address the requirements expressed in the OEP, in particular the motivators that recognized that very independent MFEs present challenges that become hard to manage as the number of MFEs grow. An in-depth comparison between the two platforms can be found here.