GithubHelp home page GithubHelp logo

marcodpt / microspa Goto Github PK

View Code? Open in Web Editor NEW
2.0 1.0 0.0 110 KB

A router for micro-frontends

Home Page: https://marcodpt.github.io/microspa/

JavaScript 76.94% Shell 0.13% HTML 22.94%
es6modules hash-router hash-routing hashrouter javascript micro-framework micro-frontend micro-frontends microframework microfrontend

microspa's Introduction

MicroSPA

A router for micro-frontends

  • A hash router for server-side rendered views.
  • All components are lazy-loaded, with promises and/or dynamic imports.
  • No building step, use template tag to define the routes.
  • Use custom elements to access components within routes.
  • loading, error, default (404 not found) templates are available.

Usage

Live Demo

<html>
  <head>
    <script type="module">
      import microspa from "https://cdn.jsdelivr.net/gh/marcodpt/microspa/index.js"

      /*
        Here we are defining the root of the router:
        <main id="app">

        And we set 4 custom elements: 
        <ms-ticker>: vanilla JS,
        <ms-counter>: Superfine,
        <ms-todo>: Hyperapp,
        <ms-error>: throw error or reject promise
      */
      window.stop = microspa(document.getElementById('app'), {
        ticker: './components/ticker.js',
        counter: './components/counter.js',
        todo: './components/todo.js',
        error: './components/error.js' 
      })
    </script>
  </head>
  <body>
    <nav>
      <!--
        This navigate to:
        <main id="app">
      -->
      <a href="#/">Home</a> |

      <!--
        This navigate to:
          <template data-path="#/todo">
        The value will be:
          plant a tree
      -->
      <a href="#/todo?value=plant%20a%20tree">Todo</a> |

      <!--
        This navigate to:
        <template data-path="#/tickers">
      -->
      <a href="#/tickers">2 tickers</a> |

      <!--
        This navigate to:
        <template data-path="#/counter/:start">
      -->
      <a href="#/counter/7?start=9&x=11">3 Counters</a> |

      <!--
        This navigate to:
        <template data-path="#/error">
      -->
      <a href="#/error">Error example</a> |

      <!--
        This navigate to:
        <template data-default>
      -->
      <a href="#/this/is/404">Not Founded</a> |

      <!--This completely stops the router -->
      <a href="javascript:;" onclick="stop()">Stop Router</a>
    </nav>

    <!--
      This is the root of the router,
      by default #/ but you can add a
      data-path attibute.
      The `ms-todo` will start with:
        read a book
    -->
    <main id="app">
      <h1>MicroSPA</h1>
      <p>Hello world! From MicroSPA</p>
      <ms-todo value="read a book"></ms-todo>
    </main>

    <!-- This is a single component route -->
    <template data-path="#/todo">
      <ms-todo></ms-todo>
    </template>

    <template data-path="#/tickers">
      <h1> 2 tickers</h1>

      <!--
        This ticker will start with
        query param `start` or default 0
      -->
      <ms-ticker></ms-ticker>

      <!--This ticker will start always with 10-->
      <ms-ticker start="10"></ms-ticker>
    </template>


    <!--
      The nav link will set the hash to:
      #/counter/7?start=9&x=11
    -->
    <template data-path="#/counter/:start">
      <!--
        starts with 7,
        path has higher priority than query.
      -->
      <ms-counter></ms-counter>

      <!--
        starts with 1,
        attributes has the highest priority.
      -->
      <ms-counter start="1"></ms-counter>

      <!--
        start with 11,
        data-start="x" sets the `start` to `x`.
      -->
      <ms-counter data-start="x"></ms-counter>
    </template>


    <template data-path="#/error">
      <!--
        Display <h1>Custom loading...</h1> for 2s,
        then reject with <template data-error>
      -->
      <ms-error message="first error" delay="2">
        <h1>Custom loading...</h1>
      </ms-error>

      <!--
        Display <template data-loading> for 1s,
        then reject with <template data-error>
      -->
      <ms-error message="second error" delay="1"></ms-error>

      <!--
        Throws an error and
        display <template data-error>
      -->
      <ms-error message="third error"></ms-error>

      <!--
        Throws an error and
        display <h1>Custom error</h1>
      -->
      <ms-error
        message="fourth error"
        error="<h1>Custom error</h1>"
      ></ms-error>
    </template>

    <!--
      This route will be displayed every time
      the router does not match any route
    -->
    <template data-default>
      <h1>Not Found!</h1>
      <p>Sorry, page not found. <a href="#/">Go home</a></p>
    </template>

    <!--
      This template will be displayed inside a custom element,
      if it reject the promise or throw an error
      and has no error attribute
    -->
    <template data-error>
      <h1>Error!</h1>
      <p>Error executing script!</p>
      <p>Please check browser logs!</p>
    </template>

    <!--
      This template will be displayed inside a custom element,
      if it is loading and it has no innerHTML.
    -->
    <template data-loading>
      <h1>Loading...</h1>
    </template>
  </body>
</html>

microspa(root, components) -> promise stop?

Note that microspa is also a component.

DOM element root

The DOM element where the router should be mounted.

Object components

An object where the keys are the component names and the values are component functions or strings with a URL to an import.

The name of the components must be written in camel case, and you can use the name of the routes object that way. But if you use it in an html view, it will convert to kebab case starting with ms-.

someComp -> ms-some-comp

Fn stop

A function that stops the router. It will call the stop function of all components on the screen, and then the router will stop.

Component

Definition:

Component(element, params) -> promise stop?

  • element: The DOM element where it should be mounted.
  • params: An object with the params passed to the component.
  • stop: An optional function that stops the component when it is called.

Example:

const ticker = (root, {start, delay}) => {
  start = (isNaN(start) ? 0 : parseInt(start)) - 1
  const update = () => {
    root.innerHTML = `<h1>Tick: ${++start}</h1>`
    console.log('tick: '+start)
  }
  update()
  const interval = setInterval(update, (delay || 1) * 1000)
  return () => {clearInterval(interval)}
}

This definition should handle the custom element case:

<ms-ticker count="20" delay="3"></ms-ticker>

And it should also handle the case of the url:

#/ticker?count=20&delay=3

Another example:

const counter = (node, {start}) => import("https://unpkg.com/superfine")
  .then(({h, text, patch}) => {
    const setState = state => patch(
      node,
      h(node.tagName.toLowerCase(), {}, [
        h("h1", {}, text(state)),
        h("button", { onclick: () => setState(state - 1) }, text("-")),
        h("button", { onclick: () => setState(state + 1) }, text("+")),
      ])
    )

    setState(isNaN(start) ? 0 : parseInt(start))
  })

Here we use dynamic imports to load the framework. Ideally, all dependencies can be loaded this way. For example, you can see some similarity in this paradigm in qwik

Contributing

Everything within this documentation is tested here. And it will always like this. Any changes to the documentation, any contributions MUST be present in the tests.

It's a very simple project. Any contribution, any feedback is greatly appreciated.

microspa's People

Contributors

marcodpt avatar

Stargazers

 avatar  avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.