ZED.JS

The 532 bytes micro frontend framework

<script>function Z(a){Z[a.id]=a}Z.xhr=function(a,b,c,d,e,f,g){if(b=b||[],e=a.local&&a.local(),e)b[c||0]=a.callback?a.callback(e):e,d&&!~b.indexOf(void 0)&&d(b);else{for(g in f=new XMLHttpRequest,f.onreadystatechange=function(){4==f.readyState&&(b[c||0]=f.status==(a.status||200)?a.callback?a.callback(f.responseText):f.responseText:NaN,d&&!~b.indexOf(void 0)&&d(b))},f.open(a.method||"GET",a.url,!0),a.headers)f.setRequestHeader(g,a.headers[g]);f.send(a.body)}},Z.xhrs=function(a,b,c,d){for(d in c=a.map(function(){}),a)Z.xhr(a[d],c,d,b)};</script>

CDN's

<script src="https://cdn.jsdelivr.net/npm/zedjs/standalone/Z.min.js"></script>
<script src="https://unpkg.com/zedjs@4.0.3/standalone/Z.min.js"></script>

NPM

npm install zedjs

The Simplest Component

This simple component will inject the html of the render function, replacing the DOM element - in this example the script element itself.

HTML

<script id="app">
  Z({
    id: "app",
    render: function() {
      document.getElementById(this.id).outerHTML = 
        "<h1>Hello world!</h1>";
    }
  });
  
  Z.app.render();
</script>
  
RESULT

Component with State

You can also add "state" to be used in the render of a component.

The state will be available globally after the component is mounted using the id. eg. Z.app.state will be { name: "Paul" }

HTML

<div id="app"></div>
<script>
  Z({
    id: "app",
    render: function() {
      document.getElementById(this.id).innerHTML = 
        `<h1>Hello ${this.state.name}!</h1>`;
    },
    state: {
      name: "Paul"
    }
  });

  Z.app.render();
</script>
RESULT

Updating Components

Components can be updated by passing the id, This will then re-render that component.

HTML

<div id="app"></div>
<button onclick='Z.app.update("John")'>Update!</button>
<script>
  Z({
    id: "app",
    render: function() {
      document.getElementById(this.id).innerHTML = 
        `<h1>Hello ${this.state.name}!</h1>`;
    },
    update: function(name){
      this.state.name = name;
      this.render();
    },
    state: {
      name: "Paul"
    }
  });

  Z.app.render();
</script>
RESULT

Loading External Data

You can also load data eg. a JSON before rendering a component.

The Z.xhr function fetches the contents of a url, then a callback function fired when the resource is fetched.

other options that can be used are method (default:GET), status (default:200), body and headers as a key:value pair object.

Resources are available globally as, in this example, Z.app.state

HTML

<div id="app"></div>
<script>
  Z.xhr({
      url: "json/robert.json",
      callback: function(data) {
        Z({
          id: "app",
          render: function() {
            document.getElementById(this.id).innerHTML = 
              `<h1>${this.state.name} is ${this.state.age} years old!</h1>`;
          },
          state: JSON.parse(data)
        });

        Z.app.render();        
      }
    }
  )
</script>
RESULT

Loading External Data - Multiple sources

You can also load multiple data sources before rendering a component.

The Z.xhrs function fetches multiple sources

Resources are available globally as, in this example, Z.app.state

HTML

<div id="app"></div>
<script>
  Z.xhrs([{
      url: "json/robert.json",
      callback: function(data) {
        return JSON.parse(data);      
      }
    },
    {
      url: "json/andrew.json",
      callback: function(data) {
        return JSON.parse(data);
      }
    }],
    function(response){
      Z({
        id: "app",
        render: function() {
          document.getElementById(this.id).innerHTML = 
            this.state.map(function(person){
              return `<h1>${person.name} is ${person.age} years old!</h1>`;
            }).join("")
        },
        state: response
      });

      Z.app.render();         
    }
  )
</script>
RESULT

Loading External Data and Caching

If you want to store data eg. using localStorage, there is a way to first query if there is local data before making a request

If the local method returns falsy, the request will be made, otherwise the returned data from the localStorage will be passed to the callback function.

HTML

<div id="app"></div>
<script>
  Z.xhr({
      url: "json/robert.json",
      local: function(){
        return localStorage.getItem("robert");
      },
      callback: function(data) {
        localStorage.setItem("robert", data)
        Z({
          id: "app",
          render: function() {
            document.getElementById(this.id).innerHTML = 
              `<h1>${this.state.name} is ${this.state.age} years old!</h1>`;
          },
          state: JSON.parse(data)
        });

        Z.app.render();
      }
    }
  )
</script>
RESULT

Counter Demo

HTML

<h1>Counter Demo</h1>
<button onclick="Z.count.update(-1)">
  -
</button>
<span id="output"></span>
<button onclick="Z.count.update(1)">
  +
</button>
<script>
  Z({
    id: "count",
    render: function() {
      document.getElementById("output").innerHTML = this.amount;
    },
    update: function(inc){
      this.amount += inc;
      this.render();
    },
    amount: 0
  });
  Z.count.render();
</script>
RESULT

Todo Demo

HTML

<h1>Todo List Demo</h1>
<div id="todo-add"></div>
<div id="todo-list"></div>
<script>
  Z({
    id: "list",
    render: function() {
      document.getElementById("todo-list").innerHTML = this.todos
        .map(function(todo, index) {
          return `
            <div>
              <span>${todo}</span>
              <button onclick="Z.list.remove(${index})">remove</button>
            </div>
          `;
        })
        .join("");
    },
    todos: [],
    add: function(){
      var task = document.getElementById("task");
      this.todos.push(task.value);
      task.value = "";
      this.render();
    },
    remove: function(index){
      this.todos.splice(index, 1);
      this.render();
    }
  });
  Z.list.render();

  Z({
    id: "task",
    render: function() {
      document.getElementById("todo-add").outerHTML = `
        <input id="task" type="text" placeholder="add task" />
        <button onclick=Z.list.add()>Add</button>
      `;
    }
  });
  Z.task.render();

</script>
RESULT

Try the sandbox for a bigger playground :)