@e1011/core-micro-frontend
v1.0.2
Published
Micro frontend framework, based on web component
Downloads
59
Readme
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 ofCMFType
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 ornull
ifwindow
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
Show your support
Give a ⭐️ if this project helped you!
This README was generated with ❤️ by readme-md-generator