Skip to main content
Version: 2.x

Step 7: Cross Communication

Let's associate the increment of a number to the click event on the Click Me! button of the custom parcel. Let's also assume we would like to pass such number as a state across micro-lc.

Every webcomponent mounted via compose integration mode, and every parcel have access to a shared, extendable API.

micro-lc API has methods to extend itself. We can add a shared feature like a counter

var microlcApi // = defined here

microlcApi.setExtension(
'counter',
{
get() {
return this.state
},
increment() {
this.state += 1
window.dispatchEvent(
new CustomEvent('increment-counter', { detail: this.state })
)
},
state: 0,
subscribe(handler) {
window.addEventListener('increment-counter', (e) => handler(e.detail))
},
}
)

and then retrieve the extension somewhere else

var microlcApi // = defined here

const {counter} = microlcApi.getExtensions()

console.log(counter.get()) // prints 0

Let's embed it in out custom parcel by retrieving the micro-lc API from the mount arguments

main.js
(() => {
// ... rest of the code

const mount = async (props) => {
container = props.container

// 👇 get the API
const {microlcApi} = props
// 👇 set the extension
const extensions = microlcApi.setExtension(
'counter',
{
get() {
return this.state
},
increment() {
this.state += 1
window.dispatchEvent(
new CustomEvent('increment-counter', { detail: this.state })
)
},
state: 0,
subscribe(handler) {
window.addEventListener('increment-counter', (e) => handler(e.detail))
}
}
)

const div = window.document.createElement('div')
const button = window.document.createElement('button')
Object.assign(
div.style,
{
alignItems: 'center',
display: 'flex',
flexDirection: 'column',
height: '100%',
justifyContent: 'center',
textAlign: 'center',
}
)

button.textContent = '+1' // 👈 better label
button.onclick = () => extensions.counter.increment() // 👈 increment counter

div.appendChild(button)
props.container.appendChild(div)

return null
}

// ... rest of the code
})()

Then we can fix some CSS

{
"sources": [...],
"content": {
"tag": "div",
"attributes": {
"style": "display: flex; justify-content: space-around; height: inherit;" 👈 some height here
},
"content": [
{
"tag": "microfrontend-loader",
"attributes": {
"style": "flex-grow: 1; background-color: #e6f7ff;" 👈 fancy background here
},
"properties": {
"application": {
"integrationMode": "parcel",
"entry": {
"scripts": [
"📄 paste base64 main.js code here" 👈 paste code
]
}
}
}
},
{
"tag": "microfrontend-loader",
"attributes": {
"style": "flex-grow: 1;"
},
"properties": {
"application": {
"integrationMode": "parcel",
"entry": "https://cdn.mia-platform.eu/micro-lc/examples/0.1.3/static/parcels/react-memory-router/index.html"
}
}
}
]
}
}

Let's then embed another custom parcel application with a number display, on the right handside, instead of the in-memory router React parcel.

display.js
(() => {
// 🧱 mount application here
let container = null

// define the 'exports' object
const exports = {}
window['display-parcel'] = exports

// define the parcel lifecycle
// 👇 bootstrap
const bootstrap = async () => null

// 👇 mount: called when route is activated
const mount = async (props) => {
container = props.container

// 👇 get the API
const { microlcApi } = props

const div = window.document.createElement('div')
div.textContent = '0'
microlcApi.getExtensions().counter.subscribe((count) => {div.textContent = count})
Object.assign(div.style, {
alignItems: 'center',
display: 'flex',
flexDirection: 'column',
height: '100%',
justifyContent: 'center',
textAlign: 'center',
})
props.container.appendChild(div)

return null
}

// 👇 unmount: called when another route is activated
const unmount = async () => {
if (container !== null) {
container.childNodes.forEach((element) => element.remove())
}

return (container = null)
}

exports.bootstrap = bootstrap
exports.mount = mount
exports.unmount = unmount
})()

again by using the data protocol we can add it on the right side

{
"sources": [...],
"content": {
"tag": "div",
"attributes": {
"style": "display: flex; justify-content: space-around; height: inherit;"
},
"content": [
{
...
},
{
"tag": "microfrontend-loader",
"attributes": {
"style": "flex-grow: 1; background-color: #fffcdd" 👈 another fancy background here
},
"properties": {
"application": {
"integrationMode": "parcel",
"entry": {
"scripts": [
"📄 paste base64 display.js code here" 👈 paste code
]
}
}
}
}
]
}
}

and by click on the left it adds to the counter on the right.

micro-lc API supports several methods and actions that out of the box let you interact with the page.

Mainly, it allows to retrieve the overall configuration, the current application, routing APIs and more...

Using the micro-lc API allows cross communication between any parcel or compose application and the layout of micro-lc and also state persistence amongst microfrontend applications whether mounted or not.