1.0.2 • Published 1 year ago

@e1011/core-micro-frontend v1.0.2

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

VeraCode Micro Frontend tooling library

šŸ  Homepage

Install and use

Install

npm add core-micro-frontend

Use

import in the file where cmf-wrapper is instantiated

import { cmf } from 'core-micro-frontend';

cmf();

or link the UMD bundle (downloadable from this repository, or server from voltron in future...) umd/cmf-bundle.js

and link in the html of your app or page...

<script type="text/javascript" src="./cmf-bundle.js"></script>

Note: when using web components in Typescript project, the custom elements must be declared, e.g.:

declare global {
  namespace JSX {
    interface IntrinsicElements {
      'cmf-wrapper': CMFWrapperType
    }
  }
}

when importin cmf-wrapper from the core-micro-frontend the declaration is part of the types in library already...

actual instantiation inside HTML, JSX:

  <cmf-wrapper
    jsFiles={JSON.stringify([JS_URL])}
    cssFiles={JSON.stringify([CSS_URL])}
    // identifiyng this instance of cmf-wrapper and making it unique in the DOM, when mupliple instances of the same mdoule (from the smae JS_URL) are loaded
    mountId='my-component-id'
    // useful if bundle in JS_URL defines this custom element...
    mountTag='my-component'
    loader
  />

Example of muplitple JS and css files:

  <cmf-wrapper
    jsFiles={JSON.stringify([JS_URL, JS_URL_LIB])}
    cssFiles={JSON.stringify([CSS_URL, CSS_URL_FONTS])}
    mountId='my-component-id'
    // bundle in JS_URL declares this custom element...
    mountTag='my-component'
    loader
  />

CMFWrapper

  • Is a custom element (i.e. web component), that will handle load of JS and CSS files of your library/module bundle.
  • loads JS, CSS in non blocking way, either via fetch and then encapsualates loaded JS in IIFE (https://developer.mozilla.org/en-US/docs/Glossary/IIFE), and injects two params: loadedJSMountPointId and loadedJSAPI

    • loadedJSMountPointId is key where to find created HTMLElement to mount your application UI tree (react, angular,...)
    • declare anywhere, but preferably before referencing:
    • declare let loadedJSMountPointId: string;
      
      declare let loadedJSAPI: Record<string, unknown>;

      or in case of Javascript, global variables dont need special declration, but we need to overcome lintint errors, on such way is adding this simple comment:

       /*global loadedJSMountPointId, loadedJSAPI */

The reference to the root/mounting HTMLElement is obtained in the loaded module:

const mountElement = window.cmf[Symbol.for(loadedJSMountPointId) as typeof Symbol];

window.cmf is namespace for this library, will hold references to all CMF wrappers in the parent app/page. Eventually could also hold reference to some communication channel or eventBus etc.

loadedJSAPI is object of serializable information, pertinent to the loaded module, and coming from the CUIModule interface. Plus config property, which is deserialized config attribute from cmf-wrapper. (config is also passed in serialized form to the mounting div (of id mountId) created by cmf wrapper or custom element of value from mountTag)

export type LoadedJSAPI = Pick<CUIModule, 'jsFiles' | 'cssFiles' | 'mountId' | 'mountTag' | 'config'>;

CMFWrapper extends HTMLElement

  /**
   * An array of JavaScript file URLs to load for the module/app.
   */
  jsFiles: string[] | null

  /**
   * An array of CSS file URLs, not mandatory CSS files custom to the JS files above.
   */
  cssFiles: string[] | null

  /**
   * The ID of the element to which the loaded JS module should mount.
   * If `mountTag` is filled, `mountId` is optional.
   * The custom element will have an ID of either `mountId` or `mountTag`.
   */
  mountId: string | null

  /**
   * The name of the element to create by CMF wrapper, in case loaded modules declare a custom element.
   */
  mountTag: string | null

  /**
   * Specifies whether to add the 'nomodule' attribute to the script tag
   * (not recommended for older browser compatibility).
   */
  esmodule: boolean

  /**
   * Prevents the creation of a shadow root (only for debugging or special cases).
   */
  noshadow: boolean

  /**
   * Specifies whether to load JavaScript and CSS via `src` and `href` attributes in script and link tags respectively.
   */
  inline: boolean

  /**
   * Specifies whether the CMF wrapper is responsible for inserting loader UI into the mount element.
   */
  loader: boolean

  /**
   * The custom event type dispatched from JavaScript when the module is done and ready.
   */
  cmfEventName: string | null

  /**
   * Additional parameters passed to the CMF wrapper's `config` attribute.
   */
  config?: string | null

  /**
   * Arbitrary `data-*` attributes that will be propagated to the created `div` element
   * with the ID of `mountId` or custom element of `mountTag`.
   * @see [HTMLElement.dataset](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset)
   * @experimental
   */
  nonce?: string

  /**
   * For non inline link and script tags, hides mountPoint element till all js and css files are loaded.
   */
  nonInlineHideUntilLoaded?: boolean

Versions

  • ES module exports version as constant
import { cmf, version } from 'core-micro-frontend';

cmf();

console.log('CMF version', version);
  • UMD bundle has version baked in as firstline comment
// cmf-wrapper version 1.0.30;
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define
....

CMF Namespace

The CMF (CoreUI Micro Frontend) namespace is a TypeScript module for managing and configuring micro frontends within your web application. This namespace provides a structured way to handle configurations, version management, and mount points for micro frontend modules.

createCMFNameSpace

Description

This function creates the CMF namespace and returns an instance of CMFType. It sets up the CMF instance with default values and proxies for various properties.

Returns

  • CMFType: An instance of CMFType representing the CMF namespace.

Example

import { createCMFNameSpace } from './webComponentWrapper';

const cmf = createCMFNameSpace();

getCMFNamespace (or getCMFWindowNamespace)

Description

This function retrieves or creates the CMF window namespace. If the window object is defined, it returns the existing CMF namespace or creates a new one if it doesn't exist.

Returns

  • CMFType | null: The CMF window namespace or null if window is undefined.

Example

import { getCMFNamespace } from './webComponentWrapper';

const cmf = getCMFNamespace();

if (cmf) {
  // You can now use the CMF namespace.
  console.log(cmf.versions);
}

CMF Type

The CMFType represents the structure of the CMF namespace and includes the following properties and methods:

/**
   * Stores the version information for different components or modules within the CMF.
   */
  versions: Record<string, unknown>

  /**
   * Maintains a record of mounting points (HTML elements) for various components or modules.
   */
  mountPoints: Record<symbol, HTMLElement>

  /**
   * Internal instance of CMF, containing version and optional wrapper information.
   */
  __instanceCMF: {
    version: string
    CMFWrapper?: CMFWrapperType
  }

  /**
   * Adds application-specific configuration to the CMF.
   * @param appId  The unique identifier for the application. Defaults to 'CMF_APP'.
   * @param config The configuration object for the application.
   * @returns `void` or `boolean` indicating success or failure of the operation.
   */
  addAppConfig: <T = DefaultConfig>(appId?: string, config: CMFConfigType<T>) => void | boolean

  /**
   * Retrieves the configuration for a specific application by its ID.
   * @param appId  The unique identifier for the application. Defaults to 'CMF_APP'.
   * @returns The configuration object for the specified application.
   */
  getAppConfig: <T = DefaultConfig>(appId?: string) => CMFConfigType<T>

  /**
   * Adds user-specific information to the application configuration in CMF.
   * @param appId  The unique identifier for the application. Defaults to 'CMF_APP'.
   * @param config The user-specific configuration object.
   * @returns `void` or `boolean` indicating success or failure of the operation.
   */
  addAppUserInfo: <T = DefaultUserConfig>(appId?: string, config: CMFUserType<T>) => void | boolean

  /**
   * Retrieves user-specific information for a specific application by its ID.
   * @param appId  The unique identifier for the application. Defaults to 'CMF_APP'.
   * @returns The user-specific configuration object for the specified application.
   */
  getAppUserInfo: <T = DefaultUserConfig>(appId?: string) => CMFUserType<T>

  /**
   * Optional: Instance of PeregrineMQApi, if integrated within CMF.
   */
  peregrineMQ?: PeregrineMQApi

  /**
   * A collection of helper functions or utilities used within CMF.
   */
  helpers?: Record<string | symbol, (...rest: any[]) => any>

Global Window Object

The CMF namespace is intended to be used as a global object attached to the window object in a browser environment. When you include the CMF namespace, it augments the global window object with the following property:

  • cmf: The CMF namespace (CMFType).

Example

// After including the CMF namespace, you can access it globally as follows:
window.cmf.addAppConfig('myApp', { /* ... */ });

// access the saved config
window.cmf.getAppConfig('myApp');

// getCMFNamespace() is shorthand for window.cmf
// acces userInfo when loaded in CMF_MOTHER_APP:
getCMFNamespace().getAppUserInfo('CUI-CMF_MOTHER_APP');

Please ensure that you include the CMF namespace appropriately in your application and follow the provided documentation to manage micro frontends effectively.

Versions

  • ES, UMD have accessible versions as map of actual CMFWrapper classes (incase of multiple versions in one page)
window.cmf.versions['1.30.0']

Mount points

Known limitations

As this is web component with shadow dom, all limitations arise from that.

  • React Bootstrap: Some libraries create new Elements as high in DOM tree as possible (Modal in React bootstrap), this can be adjusted by container property
  • event bubling is limited
  • not all styling is able to penetrate shadowdom
  • event listener targets
  • etc.

Development of this library:

Install

npm install

Run tests

npm run test

Run lint and tests

npm run prepush

Run build

npm run build

build will run prepush as well

Author

šŸ‘¤ martin.weiser@gmail.com

Show your support

Give a ā­ļø if this project helped you!


This README was generated with ā¤ļø by readme-md-generator

1.0.2

1 year ago

1.0.1

1 year ago

1.0.0

1 year ago