glaze-ui

Glaze UI is a framework that lets you have multiple Micro Front-End (MFE) applications on the same Single Page Application (SPA). That means you can have different frameworks like React, Angular and Vue running side-by-side. Including different versions o

Usage no npm install needed!

<script type="module">
  import glazeUi from 'https://cdn.skypack.dev/glaze-ui';
</script>

README

Glaze UI

  Join the chat on Discord

A framework for micro front-end services (MFE)

Glaze UI is a framework that lets you have multiple Micro Front-End (MFE) applications on the same Single Page Application (SPA). That means you can have different frameworks like React, Angular and Vue running side-by-side. Including different versions of the same framework.

It consists on a Glaze UI shell application that can host multiple MFE applications.

Motivation

Glaze UI was designed for the ever changing world of front-end applications that currently face a challenge creating a modular approach and combining different frameworks into a same single page application.

All other MFE frameworks availabe are complex to use. Glaze UI was designed with simplicity in mind, but also functionality and extensibility.

Examples

Multiple React Apps

More examples coming soon

Github: https://github.com/yoda-libs/glaze-ui-examples



Quick Start


Shell application

To create the shell application, run the command below.
For more information, refer to create-glaze-ui npm package.

yarn create glaze-ui <name> # or npx create-glaze-ui <name>

React micro front-end

To create a react micro-front end react app for glaze, run the command below.
For more information, refer to create-glaze-ui-react npm package.

yarn create glaze-ui-react <app> # or npx create-glaze-ui-react <app>

Angular micro front-end

COMING SOON

Vue micro front-end

COMING SOON



Shell Application Example

Here is an example of the shell application index.jsx file, registering navbar as a MFE React application.

import { 
    bootstrap, 
    createApps, app, 
    createRoutes, route
} from 'glaze-ui';

const apps = createApps([
    // run 'yarn create glaze-ui-react navbar' to create the navbar app
    // run 'cd navbar && yarn start'
    // in production replace the url below with the deployed production url
    app('navbar', 'http://localhost:8081/navbar.js'),
    
    // add additional apps here
]);

const router = createRoutes([
    route('/', apps['navbar']),

    // add additional routes here
])

bootstrap({
    container: document.getElementById('root'),
    apps,
    router,
    sharedLibs: {
        'react': 'https://unpkg.com/react@17.0.2/umd/react.production.min.js',
        'react-dom': 'https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js',
    }
}).then(async glaze => {
    // example on how to send a message to all glaze apps
    glaze.dispatch({test: "message"});
}).catch(console.error);



Table of contents



Registering Apps

Use createApps function to register MFE apps.

createApps takes an array of app and returns a Dictionary with the app name as the key and the app reference as the value.

const apps = createApps([
    app('navbar', 'http://acme.com/navbar.js')
])

createApps

  • Input:
    • app[]: array of app.

app

  • Inputs:

    • name: (string) - the application name.

    • bootstrap: (string | Bootstrap) - a string or an object with mount and unmount functions.

      Bootstrap

      {
          mount: (container, props) => HTMLElement,
          unmount: (container, app) => void
      }
      

    Examples:

    Register the mount and unmount functions.

    app('navbar', () => {
        mount: (container, props) => {
            const div = <div>Example MFE app</div>;
            
            container.appendChild(div);
            return div;
        },
        unmount: (container, app) => {
            container.removeChild(app)
        }
    })
    

    Use SystemJS to load a external module that resolves to an object with mount and unmount functions similar to the example above.

    app('navbar', () => System.import('http://acme.com/navbar.js'))
    

    Simplify by using a string that Glaze UI will use to call SystemJS like the example above.

    app('navbar', 'http://acme.com/navbar.js')
    



Creating Layouts

Use createLayout function to create a layout. Layouts are used in routes.

const rootLayout = createLayout(
    <div className="row">
        <div id="navbar" />
        <div id="content" />
    </div>,
    {
        navbar: apps['navbar'],
        content: apps['content']
    }
)

const notFoundLayout = createLayout(
  <h1>404 Not Found</h1>
)

createLayout

  • Inputs:
    • template: (html) - an html template.

      <div id="myid" />
      
    • apps: (Dictionary) - a dictionary that maps the html element id to a reference of the app.

      myid: apps['navbar']
      

Registering Routes

Use createRoutes function to register routes for MFE apps.

const router = createRoutes([
    route('/', rootLayout),
    route('/login', apps['login']),
    defaultRoute(notFoundLayout)
])

createRoutes

  • Input:

    • Middleware<Context>[]: array of Middlewares.

    Middleware can be route, defaultRoute or a custom function (context, next) => void.

route

Defines an app or a layout to render when url starts with the specified path.

  • Inputs:

    • path: (string) - the route path.

    • appOrLayout: (app | layout) - a reference to an app or layout.

      Examples:

      Register route with an app reference.

      route('/', apps['navbar'])
      

      Register route with a layout.

      route('/', createLayout(
          <div className="row">
              <div id="navbar"></div>
              <div className="col">
                  <div id="left"></div>
                  <div id="right"></div>
              </div>
          </div>, {
              navbar: apps['navbar'],
              left: apps['left'],
              right: apps['right'],
          })
      )
      

    defaultRoute

    Defines the an app or layout that will load if no other routes are a match.

    • Inputs:
      • appOrLayout: (app | layout) - a reference to an app or layout.

        Examples:

        Register default route with a 404 layout.

        defaultRoute(notFoundLayout)
        

        Register default route inline.

        defaultRoute(createLayout(<h1>404 Not Found</h1>))
        

    custom middleware

    Defines a custom middleware.

    • Inputs:
      • function: (context, next) - a function that takes context and a next function.

        • context
          • path: (string) - the url path.
          • state: (object) - an object with state.
          • matches: (object) - an object with score and layout.
            • score: (number) - a number that gives a score to the match.
            • layout: (layout) - the layout that matches the url path.
        • next: (function) - a function that calls the next middleware.

        Examples:

        An authentication middleware.

        const authMiddleware = async (context, next) => {
          if (context.path.startsWith('/login')) return next();
        
          if (context.path.startsWith('/logout')) {
              localStorage.removeItem('token');
              return await router.navigate('/login');
          }
        
          if (context.path.startsWith('/auth')) {
              const { token } = context.state;
        
              localStorage.setItem('token', token);
              return await router.navigate('/');
          }
        
          if (!localStorage.getItem('token')) 
            return await router.navigate('/login');
        
          next();
        };
        

        A simple middleware that mimics a route.

        const customRoute = (context, next) => {
          if (context.path.startsWith('/custom')) {
            context.matches.push({
              score: 50,
              layout: createLayout(<h1>Custom Page</h1>)
            });
          }
          next();
        }
        

Bootstraping

Use bootstrap function to initialize the library and bootstrap components. Returns a Promise that resolves to an instance of Glaze.

bootstrap({
    container: document.getElementById('root'),
    apps,
    router,
})

bootstrap

  • Inputs:
    • config: (BootstrapConfig) - the configuration object.

      BootstrapConfig

      • container: (HTMLElement) - the root html element for Glaze UI to render.
        document.getElementById('root')
        
      • apps: (app[]) - the list of apps. Plese refer to createApps.
      • router: (Router) - a reference to a router. Please refer to createRoutes.
      • sharedLibs: (Dictionary) - a dictionary with library urls to be shared across MFE apps.
        {
            'react': 'https://unpkg.com/react@17.0.2/umd/react.production.min.js',
            'react-dom': 'https://unpkg.com/react-dom@17.0.2/umd/react-dom.production.min.js',
        }
        
      • options: - the options.
        { debug: true }
        

      Examples:

      Most trivial example on how to bootstrap.

      bootstrap({
          container: document.getElementById('root'),
          apps
      })
      

      Bootstrap with a router and dispatches a message after.

      bootstrap({
          container: document.getElementById('root'),
          apps,
          router,
      }).then(async glaze => {
          // example on how to send a message to all glaze apps
          glaze.dispatch({test: "message"});
      })