With Collage you can upgrade a web application of all sorts to either a micro frontend or an application capable of embedding micro frontends - basically both at the same time. Doing so, Collage works on the scope of HTML Documents by enhancing a Document with certain capabilities, allowing them to efficiently communicate with each other.
An HTML Document enhanced this way is called a context
Behind the scenes Collage relies on iframe integration and the postMessage api.
When using Collage to create and embed micro frontends, always consider the common security rules for iframes.
Here is a quick overview: https://blogs.halodoc.io/iframe-security-threats-and-the-prevention/
If we look at an application like in following picture, then we see a collage, which consists of several parts. There is the application frame, which we call an arrangement. The arrangement can embed one or several micro frontends, which we also call fragment. This fragment can embed another fragment. As soon as a fragment embeds another, we call it fragment and simultanously arrangement.
By calling the expose function, an HTML Document is automatically upgraded to a context. Being a context comes with two main features:
- A context can embed other contexts
- A context can be embedded into other contexts
This means, a context is always both an application embedding micro frontends and an embeddable micro frontend. The responsibility a context gets in your application depends on its relation to other contexts. A context that embeds one or more other contexts is called an arrangement, a context that is embedded by an arrangement is called a fragment.
An arrangement defines the layout and configuration of it's embedded fragments and is able to use the Direct Functions API to communicat with its fragments directly.
An arrangement can be a fragment itself and thus be embedded into other arrangements.
Any Micro Frontend with an initialized context (by calling expose
) is called a fragment.
A fragment defines its internal layout and exposes capabilities and properties to the arrangement via the Frontend Description Object.
The capabilities and features of a context are defined and described by its Frontend Description. These can be Services, Topics, Direct Functions or a Theme.
Services are a request response communication mechanism.
A Service is a function or a collection of functions and topics and is uniquely identified by its name and (optionally) version. With a Service, you can easily provide functionality to other fragments. This especially comes in handy when you want to provide application functionality like notification handles or modal dialogs to fragments.
Services have certain attributes and restrictions:
- Two implementations of a Service must always be compatible with each other, e.g. by implementing the same specification.
- Every service exposed by a context is registered within Collage and kept synchronous between all contexts in the arrangement.
- If a context in the application is calling a specific service, always the implementation of the context that registered the Service topmost in the DOM tree is called. This means, that if a service is provided by each a fragment and its arrangement, always the implementation registered at the arrangement will be executed.
- The return value of the implementation is communicated back to the context initially calling the Service.
- A context can expose any number of Services via its Frontend Description.
- A Service is always provided to the whole Application.
- If a context wants to use a service, it must provide an own implementation itself. This is necessary, because all fragments must be self contained.
- A Service can be imported or implemented in the context.
Keep in mind, that it is possible to use a provided service from any embedded fragment (and also fragments embedded in fragments). So think twice about the data you want to communicate via services.
If your fragment depends on data received via a service, it never should trust these data blindly, but should validate them.
Don't use services to work around origin restrictions (e.g. SOP or Same Site Cookie Restrictions).
Topics are a publish subscribe communication mechanism. They are an efficient way to communicate messages to the whole application.
To do so, a context can publish a message on that topic. Any other context, that has subscribed to that topic gets the message and can react appropriately to the message.
Information about how to use topics are found in the Topics API section of the API documentation.
A fragment should always be able to be used standalone, meaning without an arrangement embedding it.
Therefor it must implement all Services it wants to use in its lifecycle.
It should also be designed in such a way, that a meaningful user interaction can be provided, even when the fragment is interacted with on its own.
Comming Soon
The concept and Api descript here is NOT yet part of the current version of Collage. Is WILL however be implemented in the near future.
Wording and Api itself should be considered subject to change, until the feature is implemented.
Collage will take care of seamlessly integrating the different fragments of any arrangement via Style Synchronisation.
To this end, a fragment will be able to mark any <style>
or <link rel="stylesheet'>
elements as a collage-theme
<html>
<head>
<!-- ... -->
<link rel="stylesheet" url="/some/style.css" data-collage-theme>
<style data-collage-theme>
/** ... */
</style>
</head>
<body>
<!-- ... -->
<!-- works in the body as well -->
<style data-collage-theme>
/** ... */
</style>
</body>
</html>
Elements marked as collage-theme
will get propagated from an arrangement, down to it's contained fragments. This will happen before the fragment initializes its contained fragments (if any) so the styles will cascade down to fragments that are deeper embedded.
Propagated elements will be put at the end of either the <head>
or <body>
tag, depending on which containing tag it originated from. Older propagated elements (from higher up the hierarchy) will be in front of newer ones and we will keep the internal order of where they have been placed intact.
In a case where the app author knowingly updates some style, he will be able to directly/manually trigger a style repropagation from the API.
We will try and find a way to automatically detect updates to those elements and retrigger the style propagation if an update occours. However, since we anticipate this automatical detection to become a bit expensive, there will be a way to opt out of automatic repropagation in which case only the initial propagation will trigger automatically and the app author has to manually trigger repropagation if he wants to dynamcally update styling later on.
Further more: style propagation can be oppted out on, if you like to follow a different route on keeping your styles in sync. In a deeper hierarchy of arrangements this will then stop propagation at the exact branch where style propagation was stopped. If you stop style propagation from an arrangement but still mark style elements as collage-theme
within that same arrangement document, a new propagation will occour, collecting only the styles from that arrangement down.
Exposing a frontend to be used as a fragment
in other arrangements
and initializing a context for a frontend to orchestrate child fragments
with is always done in tandem. Meaning you can't have one without the other.
To initialize your frontend and start using Collage
functionality, first describe frontend with a Frontend Description object the topics, style variables and functions this specific frontend is interacting with as well as a config containing metadata to describe your frontend.
const {
fragments: { myChild },
services,
} = expose({
fragmentsConfig: {
name: "My awesome frontend",
version: "1.0.0",
},
services: {
bazz: {
bar: () => {},
topics: ["foo", "bar", "baz"],
}
}
functions: {
foo: () => {},
bar: (baz) => {
console.log(baz);
},
},
});
Functions exposed directly by your child frontend are accessible in the initialization context
via the name you gave the child whilst defining the collage-fragment
element for it.
This behaviour enables you to explicitly expose your children's functions as your own, so that postential parent applications can call those functions on your context later.
It also enables you to interact with child functionality while composing your own functions or define abstraction layers between your and your childrens' function contracts.
collage.expose((fragments) => {
// interact with your children via the name you gave them in the html
return {
/* ... */
functions: {
/**
* forward the `something()` function call to your `foo` child
*/
something: fragments.foo.something,
/**
* use child functionality in your own functions
*/
anotherthing: (times) => {
[...Array(5)].forEach(fragments.foo.bother("Hi!"));
},
},
};
});