The integration of the various apps (i.e. micro frontends) is achieved with an <iframe>
, see ADR 2: App Integration via iframe for more details on this decision. The <iframe>
is rendered in the <bkd-content> component. However, this method comes with some trade-offs & issues.
The public/scripts/iframe.js script solves most of these issues and has to be included in an app's index.html
. It sets up communication between portal & iframe and initializes workarounds.
Apps can use client-side hash-routing, that means using the hash part of the URL to store application state. The Evento Portal ensures, that the hash part is mapped from the <iframe>
's URL to the URL in the browser's location bar and vice versa. This synchronization is achieved as follows:
iframe.js
: Wraps the history API in the iframe to post messages about state changes to the Evento Portal:history.pushState
in iframe →bkdAppPushState
message in portalhistory.replaceState
in iframe →bkdAppReplaceState
message in portalhashchange
event in iframe →bkdAppHashChange
message in portal
<bkd-portal>
component: Registers the above message events and updates the portal state & URL. It also registers thehashchange
event to propagate changes of the browser's URL to the iframe URL.
Since an iframe has a fixed size, its width & height have to be constantly adjusted to the app's document/contents. A special challenge are absolute positioned elements (like dropdowns or overlays) that just overflow if larger than the document and not cause the document to grow.
The resizing of the iframe is implemented as such:
iframe.js
: AResizeObserver
is used to track changes to the overall height of the app's document. AbkdAppResize
message is posted if the height changes.iframe.js
: AMutationObserver
is used to track the addition or removal of any absolute positioned nodes and to determine the bottom most element with absolute positioning. AbkdAppResize
message is posted if the height changes.<bkd-content>
component: Registers thebkdAppResize
messages and sets the given height on the<iframe>
.
Since the iframe is constantly resized, it never has a vertical scrollbar. This is an issue when apps want to scroll programmatically. Thus, the frame.js
scripts monkey-patches the following parts of the browser API to apply the scrolling in the Evento Portal window instead, incorporating the iframe's top offset:
window.scrollTo
&window.scroll
window.scrollBy
window.scrollY
&window.pageYOffset
Element.prototype.getBoundingClientRect
Element.prototype.scrollIntoView
(an element is always top aligned, thealignToTop
,block
andinline
options are not supported)
These functions/properties can be used safely by apps. What does not work is the scroll
event.
Positioning elements relative to the viewport/scroll position – such as modal dialogs – is an issue. The CSS rule position: fixed
does not work, since the iframe is not a scrolling container (the element will stick to the top of the iframe in this case). Apps have to consider the Evento Portal window's scroll position and the iframe's offset in this case.
Checkout the BkdModalService of the webapp-schulverwaltung as an example.
The iframe.js
script applies the Evento Portal's HTML lang
attribute to the app's document.