Common UI Components with Logic — Web Components
How we tackled common UI challenges in our React and Elm-based micro-frontends
In 2019, our team at GWI started its journey with micro-frontends (MFEs) to tackle the challenges of scaling our codebase and making our teams more autonomous.
Back then, our framework of choice was single-spa(and it still is), and our main focus was on creating a seamless experience between our Elm and React-based applications. In this blog post, we’ll explore our experience with common UI components with logic — web components — and the solutions we’ve found for various challenges. So, let’s dive in!
The Challenges with Common UI Components
In the early stages of our MFEs journey, we faced the issue of common functionality needed by both Elm and React-based applications. Instead of duplicating efforts and implementing common functionality in both technologies, we decided to:
- Implement the functionality once, either in React or Elm, and wrap the output in web components for use by both languages.
2. Communicate with each MFE in the following way
- The MFE should transmit data to the common component through its HTML attributes.
- The MFE should retrieve data from the common component using the browser’s custom events.
Developing an Internal Storybook for Web Components
To make it easier for our team, including front-end engineers, project managers, and designers, we set up an internal storybook for managing web components. This central hub provided several advantages:
- Quick Development: The internal storybook allowed team members to efficiently create, review, and test web components all in one place.
- Stay Updated: By having a central location, the storybook made sure everyone was aware of the latest changes and updates to our shared UI components.
- Better Communication: The internal storybook encouraged discussions between all team members involved in the product, leading to improved collaboration and decision-making.
In summary, the internal storybook became a crucial tool for handling web components and promoting a more productive and communicative team environment.
Creating Single-Page Mini Apps
As our MFEs evolved, we realised that there was a need for single-page mini-apps that were:
- Too small for a new MFE.
- Too big for a web component.
- Able to capture the full viewport of the browser.
We explored two solutions:
Solution #1: The BlackBox Pattern for Mini Apps
In this approach, we use the BlackBox pattern to create single-page mini apps as MFEs. These black-box apps communicate with other applications through custom events and can be rendered or hidden from the DOM as needed.
Pros:
- Innovative: This pattern offers a fresh and effective way to manage mini apps.
- Centralised Code: The entire single-page mini app’s code is contained in one repository, simplifying maintenance for front-end engineers.
Cons:
- Elm Limitations: The BlackBox pattern may not work as effectively for Elm-based applications.
- Complex wiring: Front-end engineers might have to create more intricate wiring when using this mini app with other MFEs.
Solution #2: Web Components with Independent Repositories for Mini Apps
The next solution we implemented involved creating single-page mini apps as web components, regardless of their size, and providing each one with its own Git repository.
Pros:
- Effective: This method works well for creating and managing mini apps as web components.
- Centralized Code: Each mini app’s code is contained in a single repository, making it easy for front-end engineers to track and maintain.
Cons:
- Complex Wiring: Front-end engineers might need to set up more sophisticated connections when implementing these mini apps in their MFEs.
- TypeScript Drawbacks: The lack of static typing for TypeScript means that potential errors can only be caught during runtime, which might be challenging for front-end engineers to handle.
…and we are thinking of also exploring the solutions below in the near future 👇
Something changed along the way
The discontinuation of Elm in GWI’s main platform
As our development priorities and technology stack continue to evolve, we have made the decision to discontinue the usage of Elm in our main platform. Although Elm has been a valuable asset in the past, our team has recognised the benefits of adopting a unified approach to micro-frontend development with React. By focusing solely on React, we can streamline our development process, making it more efficient and maintainable in the long run as no more web-components will be needed but rather only react-based components, enabling our platform engineering teams to catch issues on build time with the usage of typescript. While we appreciate the contributions of Elm in our platform’s past, we are excited to embrace the React-centric approach and look forward to the new opportunities it presents for creating innovative, high-quality, and scalable apps.
Next steps
Solution #3: Merging Mini Apps with the most related MFE’s codebase
This method suggests embedding single-page mini-apps into their most related micro-frontend. This works for our specific scenario (don’t try this at home 😂) of sharing the same domain between an MFE and a common component.
The next step is to change the communication method from wiring to utilising the browser’s history property for communication.
Pros:
- Consolidated Repository: Combining related elements in one code repository simplifies development and organisation.
- Elm Support: Elm-based applications can effortlessly interact with the integrated mini-apps, enabling smooth teamwork.
Cons:
- Complex CI process: Establishing mini-apps within MFEs may create complex CI pipelines for proper building, testing, and deployment.
- TypeScript Limitations: Static typing for TypeScript is not available in this scenario, meaning potential errors will only be detected during runtime, which can lead to unforeseen issues.
Solution #4: Transforming Single-Page Mini Apps into Independent MFEs
In this approach, we consider elevating the single-page mini-apps to a higher level of independence by turning them into standalone micro-frontends (MFEs).
Pros:
- Distinct Code Repositories: Each mini-app benefits from having its own code repository, allowing for greater separation and management of the individual components.
- Elm Compatibility: This setup enables Elm-based applications to easily integrate with these independent mini-apps, promoting a smooth collaboration.
Cons:
- Synchronizing Updates: When such components are updated, all MFEs need to be updated to the latest version as well. This requirement may undermine one of the main advantages of MFE architecture.
- TypeScript Limitations: Static typing for TypeScript is not available in this scenario, meaning potential errors will only be detected during runtime, which can lead to unforeseen issues.
Final thoughts
In conclusion, our journey with web components has been valuable in addressing common functionality challenges between Elm and React-based applications. However, as we plan to fully adopt React and discontinue using Elm, it’s time to reassess our approach and consider new solutions for single-page mini apps.
With our focus shifting to React components, we can explore alternative strategies like Module Federation, which enables the seamless sharing of components across applications. We’re now considering implementing Solution 4, although its implementation effort might be significantly bigger compared to Solution 3.
Solution 3 integrates mini apps directly into their corresponding MFEs, streamlining communication and reducing overhead. However, Solution 4 emphasises independent MFEs, potentially leading to slower implementation.
As we move forward, it’s essential to carefully evaluate each solution’s pros and cons, considering factors such as team preferences, performance requirements, and maintainability. A good assessment will help us make an informed decision that aligns with our goals and ensures the success of our projects.
In summary, our experience with web components has equipped us with essential tools to tackle complex UI challenges. As we transition to a React-only approach, it’s crucial to explore new solutions that align with our evolving technology stack. By carefully weighing each strategy’s advantages and disadvantages, we can confidently adapt to change and innovation, ultimately creating outstanding user experiences for our audience.