DEV Community

Cover image for Assemble your own micro frontend framework
artydev
artydev

Posted on • Updated on

Assemble your own micro frontend framework

There was a time when it was common to assemble your own PC.
You chose your MotherBoards, Graphic Cards and so on.
Those times are gone for the vast majority of us...

But nothing prevents us to do the same from or with our favorites libraries.

I am very found of the Model/View/Update a.k.a Sam Pattern.

There are great libraries that take this approach ELM, HyperApp, AppRun, Meiosis (more a pattern than a library)...

But none of them satisfied me entirely, so I, decided to assemble one which fits my needs, and easily used by my colleagues who 'hate' Javascript and don't know nothing about node.js

For that I used : SinuousJS and Unistore and I create MVU.js

I created a very simple project with vite.js, and I included the following lines in the main script

import htm from 'sinuous/htm';
import { observable, subscribe } from 'sinuous/observable';
import  { render, context }  from './src/render';
import createStore from 'unistore';

const r = context()
function html() {
  return htm.apply(r, arguments);
}

const MVU =  { render, html, observable, subscribe, createStore };
window.MVU = MVU;
Enter fullscreen mode Exit fullscreen mode

The main goal was to make the View a function of the State (or Model) and nothing else.

Here is the demo of the traditional Counter

const {html, render, observable, createStore} = MVU;

const State = observable({});

const Model = createStore({
  counter : 0
});

const inc = Model.action ((model, value = 1) => {
  return ({counter : model.counter + value}); 
})

Model.subscribe(store => State(store));

function View () {
  let state = State();
  return html `
    <h1>Counter ${state.counter} </h1>
    <button id="incer">INC</button>
  `
}

function startApp () {

  Model.setState();

  render(View, document.body);

  document.getElementById("incer")
          .addEventListener("click", () => inc(1));
}

startApp()

Enter fullscreen mode Exit fullscreen mode

You can test it here : MVUCounter

See how the counter is updated, while the button is not recreated and so, we don't loose the 'click listener' on it...thanks to SinuousJS.

Unistore allows to 'react' and 'call' subscribers whenever the Model changes.

In this model, there is a clean separation from the Model and the View.
The actions are centralized in one unique point and not messing around all your code

Let's refactor a bit :

import { State } from "./state.js"
import { Actions } from "./actions.js"
import { Model } from "./model.js"

const {html, render} = MVU;

function View () {
  let state = State();
  return html `
    <h1>Counter ${state.counter || 0} </h1>
    <button onclick=${() => Actions.inc(1)}>INC</button>
  `
}

render(View, document.body);
Enter fullscreen mode Exit fullscreen mode

You can test it here SAMCounter

Go and assemble yours (or not), and tell us why you created it :-)

Top comments (0)