> For the complete documentation index, see [llms.txt](https://notes.lirenxn.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://notes.lirenxn.com/2020/wk-notes-03-09-micro-frontend-bootstrapper.md).

# Wk-notes-03-09-micro-frontend-bootstrapper

### Micro-front-end-bootstrapper <a href="#micro-front-end-bootstrapper" id="micro-front-end-bootstrapper"></a>

#### html container/anchor structure <a href="#html-containeranchor-structure" id="html-containeranchor-structure"></a>

```javascript
<div data-widget-type="WIDGET_TYPE">
  <script type="widget">
  {
      "type": "json",
      "generateFrom": "CMS(aem)",
      "purpose": "widget-config-for-feature-and-globals",
      "scope": "per-widget-container"
  }
  <script/>
<div/>
<script src="PATH/TO/BUNDLE/app.js"/>
```

It is supposed to be self contained and is possibly able to be mounted several time on on page.

#### `bundle/app.js` <a href="#bundleappjs" id="bundleappjs"></a>

**Idea: `register` as entry function, `Widget` as widget base class**

**register**

```javascript
register = (widgetType: string, widget: Widget) => {
    // widgetType as 'flight-search', 'email-subscription'
    // where we assume one widget type can be mounted several times on one page
    
    // Load config from html
    getConfiguration = (anchorContainer) => {}
    
    // Get the instance from container
    getWidgetInstance = (anchorContainer) => {}
    
    // Render widget on html
    mountWidget = (anchorContainer) => {
        widget = new Widget(id, anchorContainer, configuration);
    }
    
    // Update widget on html
    updateWidget = (anchorContainer, props) => {}
    
    // Update widget on html
    unmountWidget = (anchorContainer) => {}
    
    // render All anchorContainers (potentially multiple)
    renderAll = () => {}
    
    document.addEventListener('DOMContentLoaded', renderAll);
    document.addEventListener('load', renderAll);
}
```

**Widget**

```javascript
class Widget {
    constructor(id, anchorContainer, config){}
    
    // Called on rendering the individual widget
    render(p){
        // - React
        // return <App p={p}/>
        // - Vue ?
        // return null;
        // - Angular ?
        // return null;
    }
    
    // Defines how to mount the widget to the DOM
    renderer() {
        // - React
        // return ReactDOM.render(this.render(this.props), this.node);
        // - Vue
        // new Vue({el: this.node});
        // - Angular
        // platformBrowserDynamic().bootstrapModule(AppModule);
    }
    
    update(props) {
      this.props = props;
      // - Redux
      // this.store.dispatch();
    }
    
    unmount() {
      // - React
      // ReactDOM.unmountComponentAtNode(this.node);
    }
}
```

A base AppShell for bootstrapping, updating, and unmount.

#### Thoughts <a href="#thoughts" id="thoughts"></a>

* Check requirement, if the bootstrapper needs to support multiple mount for save widget, ideally yes
* To share a bootstrapper
  * either make a monorepo with all the widgets referencing to single bootstrapper, and bundle it with same vendor bundle (code-split and cache)
  * or make a provider(`widget-provider`) and reference it to all the package as dependencies and use the provider as the single entry point of bundles
* We do not actually need a `render()` as `react` does, it mixes react behavior with micro-frontend contracts
