Micro Encapsulation Framewrok (MEF) is a framework that supports trully encapsulated Micro Frontends (MFE). MEF can be used within a project to create pluggable Micro applications that run independently from other Micro applications on the page. MEF uses modern techniques to implement scoping for JavaScript and containment for CSS.
- Introduction
- Purpose
- Structure
- Requirements
- Installation
- Integration
- Configuration
- Usage
- Contributing
- License
Web applications are built for many purposes and use differing technologies, but no matter the technology used, all of them are constrained by the browers runtime. This constriant makes it difficult to create micro frontends that can trully run independently and orchestrate easily with other micro frontends. If we look at a Web application as a whole, these applications execute at the highest level in the browser. All global JavaSctip objects live in the window object's scope for the Web application. For the purpose of having a definition we will call the Web application that is deployed the Macro application. The Marco application is where all JavaScript runs, CSS cascades and HTML templates, patterns and components render. The Macro application is where micro frontends are declared and instantiated. Micro frontends, for the purpose of having a definition, will be called Micro applications. So the understanding at this point is that micro frontends, Micro applications, are declared and instantiated in the Web application's, Macro application's, container.
Using Micro applications has it pro's and cons. Some of the benefits we see from Mirco applications are:
- smaller, more cohesive and maintainable codebases
- more scalable organisations with decoupled, autonomous teams
- the ability to upgrade, update, or even rewrite parts of the frontend in a more incremental fashion than was previously possible
Of course, there are no magic bullets when it comes to software architecture as everything comes with a cost. Some Micro application implementations can lead to:
- duplication of dependencies
- mutliple versions of same dependencies
All which increases the number of bytes our users must download. Nevertheless risks can be managed, and the benefits of Micro applications often outweigh the costs. In short, Micro applications are all about segmenting big Web applications into smaller, more manageable chunks, and then being explicit about the dependencies between them. Our technology choices, our codebases, our teams, and our release processes should all be able to operate and evolve independently of each other, without excessive coordination.
Our ultimate goal is to take full advantage of Micro applications pro's while reducing and or alleaviating the impact of thier cons. As of today there has been discussion around several approaches to using Micro applications, a few approaches for example.
This approach is accomplished by rendering HTML on the server out of multiple templates or fragments. We have an index.html which contains any common page elements, and then uses server-side includes to plug in page-specific content from fragment HTML files.
- This approach is valid but does not solve the cons of using Micro applications.
Another approach that we sometimes see is to publish each Micro application as a package, and have the Macro application include them all as library dependencies.
- This approach could reduce the cons of using Macro Applications by using shared dependencies, but breaks the atonomy of the Micro application.
One of the simplest approaches to composing applications together in the browser is the humble iframe. By their nature, iframes make it easy to build a page out of independent sub-pages. They also offer a good degree of isolation in terms of styling and global variables not interfering with each other.
- This approach does in a minimal way handle the cons but causes changes to the Micro application having to know that MFE lives in an iframe, amongst other issues iframes entail.
The Run-time integration approach is probably the most flexible one, and the one that we see teams adopting most frequently. Each Micro application is included onto the page using a script tag, and upon load exposes a global function as its entry-point. The container application then determines which Micro application should be mounted, and calls the relevant function to tell a micro frontend when and where to render itself.
- This approach is valid and common but does not solve the cons of using Micro applications.
One variation to the previous approach is for each Micro application to define an HTML custom element for the container to instantiate, instead of defining a global function for the container to call.
- This approach has poosiblities but not only does it cause the atomnomous teams to know and understand the usage of custom elements, it does not solve all the cons of using Micro applications.
MEF was designed around some of the common approaches we see today, taking full advantage of their pro's all while reducing and or alleaviating the cons of using Micro applications. MEF uses the run-time integration via JavaScript as well as utilizing Web Component as a container. MEF allows the implementation to take two approaches, Self-Contained or Global. Choosing either direction is a decision to made based on the Macro application strategy. If the goal of the Macro application is to have all Micro applications share in the same shared assets, then the Global startegy should be used. To take advantage of shared assets using the Global strategy you would need supply the external property within the MEF config, @see Configuration. If you decide to take advantage of the Self-Contained strategy you should note that you will be including all assets within the build Micro Application. The Self-Contained strategy is the default strategy so to take advantage of it nothing extra needs to be configured. The rest of the documentation will show and describe just how MEF's two strategies, Self-Contained and Global, will not only use some of these common approaches, how MEF takes full advantage of, capitalizes on, and enhances these approaches.
MEF was designed to take advantage of Web Component technology all while elevating it's capabilities. A Web Component is a HTML Document Fragment and does not have all the features and functionality of the window document. This is a disadvangtage as the purpose of MEF is to encapsulate the Micro application so that it could run as if it was deployed directly in the window document. The idea being that when developing a Micro Application the developer does not need to know that the end solution will be within a Web Component. To correct the disadvantages of the HTML Document Fragment MEF elevates the capabilities of the Web Component so the Micro applicaion acts and feels like it is running in the window document. The way this is done is by adding all the missing elements, functions and properties of a HTML Document to the Web Component HTML Document Fragment. There many other Node frameworks that attempt this so that Node applications can run as if they where in a Browser. This is why MEF uses the definitions of Macro and Micro applications and not Web application and Microfrontend.
CSS as a language is global, inheriting, and cascading, traditionally with no module system, namespacing or encapsulation. Some of those features do exist now, but browser support is often lacking. In a Micro application landscape, many of these problems are exacerbated. For example, if one team's Micro applications has a stylesheet that says h2 { color: black; }, and another one says h2 { color: blue; }, and both these selectors are attached to the Macro application, then someone is going to be disappointed! This is not a new problem, but it's made worse by the fact that these selectors were written by different teams at different times, and the code is probably split across separate repositories, making it more difficult to discover.
CSS is deployed within the MEF container which in turn is a Web Component. Web Components inheritly encapsulate CSS, removing any bleed. This solution allows for the deployment of styles with out any impact on any other Micro applications deployed around or within the Macro application or other Micro applications. Web Components also allow for the cascading of CSS from outside, this will help reduce the need for full CSS implementations within the Micro application as styles can be inheritted. Only styles that need to be overridden or defined need to be added to the Micro application.
When developing Micro applications you could use a framework like React. For the Micro application to work React needs to be available within the application. Including the React framework within your Micro application will increase the size needed to be downloaded. This is neccessary as your application needs the framework but becomes a part of the Micro applications cons. Not only is the download bulk a con, but when other Micro applications are doing the same download using different versions of React then you now have the problem of not only duplication but multi-versions of the same framework. This problem is also another major con of developing Micro applications.
Utiling frameworks encapsulated within the Micro application allows for the multiple reuse of the Micro application across many Macro applications. This strategy is the true part of creating MFE's, self contained autonomous Micro applications. This leads to the duplication as well as unstandardized framework versions. One of the strategies mentioned before, the Global strategy, can be used to standardize on a framework and version as well. Once this strategy is put into place it causes the owner's of the Macro application to certify the deployed Micro applications. This also leads to Micro applications that can only be deployed within Macro applications that support a particular framework and possibly version. This strategy is viable but breaks the concepts of what a MFE is.
All in all MEF supports the best parts of all the approaches as well as helping to control CSS per Micro application. Needless to say there still needs to be some coordinating when using global assets. For instance if a global set of styles is set on the Macro application then Mirco application developers should understnd this and utilize this strategy as much as possible to reduce the volume of data needed to be downloaded to style the application. You can still include everything within the Micro application which will not affect any other Micro application, but the ultimate goal is to only include just what the application need to style and run.
Node npm npx
MEF supports several project types and can work with JavaScript or Typescript development. The installation instructions are to be used for creating projects from scrtach. For information on integrating MEF into and existing project see the Integration section. All MEF applications created from scratch are Node applications. The first thing todo is create a folder for the node based project.
Example:
mkdir vanilla-project-name
The folder name can be any valid Node project name. Note that when creating a Node project the folder name is usually the value used in package.json for the name property. If the folder name used is not a valid Node name, this can be changed after the Node project creation. This is possible as the Node project initialization is using 'es6'. This initialization does not force the use of the folder name as the project name and creates a package.json that is needed for MEF. Next we will cd into the folder and initialize the Node project using the following command.
Note that we are creating a modern project so the project type will be 'module'.
cd vanilla-project-name
npm init es6
Once the process has completed and package.json is availble for editing the project properties as needed. The name field within the package.json by default is used by MEF for several things like asset name(s) that are compiled, the id attribute of the div used for the container as well as the custom element's name itself. For instance using the example name 'vanilla-project-name' upon a completed build you would have two files, the client file vanilla-project-name-client.js and the main file vanilla-project-name.js. Note that the name value is used to create the Web Component so this should follow Web Component naming conventions and be unique amongst all the other Micro applications that could be deployed in the Macro application.
Next we will need to install the MEF into the project. Note that is a dev dependency as all needed code will be compiled into the assets created.
npm install --save-dev mef
or
npm i -D mef
MEF can bootstrap your project using templates. Templates allow you to quickly setup a project for using a particular technology and or framework of choice. If a template is not provided during setup, then a vanilla JavaScript project is created. During the setup several things happen:
- package.json script property is updated
- all dependencies based on the template are insatlled
The template parameter is optional but when supplied there are a few templates available for bootstraping your project, "ts", "react", "react-ts" and "angular".
- omitted : this is a default vanilla JavaScript project.
- ts : template can be used to setup a vanilla Typescript project.
- react : template can be used to setup a react JavaScript project.
- react-ts : can be used to setup a react Typescript project.
- angular: can be used to setup an angular Typescript project.
The version parameter is optional but when used along with "react", "react-ts" or "angular" templates dictates the version of the framework to be used. If the version parameter is omitted then "latest" is used to insatll the version of the framework.
Next we will run the setup command via npx.
npx mef setup
or
npx mef setup --template=ts
or
npx mef setup --template=react --version=18
or
npx mef setup -t=react-ts -v=18
or
npx mef setup -t=angular -v="18.0.4"
NOTE: when using specific versions that include periods, you need to place quotation marks around the verion numbers as shown in the last example above.
At this point
- all development dependencies based on the template have been installed
- new package scripts have been added "mef:dev" and "mef:build"
- an index.html file used with the dev server has been created
- the mef cache files has been placed in the node_modules folder
The created index.html used with the development server is an example of the runtime-integration strategy and how your MEF project can get integrated into a Macro application. Lets take a closer look into how the example can be used to create a runtime-integration into a Macro aplication. If we take a look at the below HTML example you can see there are two key factors that help facilitate the intgration. The first factor is the entry point where the developed Micro application will be mounted. This is idenetified by the HTML element that has the unique MEF id attribute assigned to it. Notice that the id attribute is the same name as either the mef configuration name property or the package.json name property, or the project's folder name. When the index.html file is generated for you during setup, it will search all the previous named locations to identify what the application name that is going to be used. If you run the setup without a MEF configuration file, or you have not updated the project's package.json name property it will default to the project's folder name. This is the order in which the MEF discovers the name for the Micro application. If at anytime any of these locations are updated this will change the outcome of the compiled assets and the index.html file should be updated to correspond to the change. This is a key to how the Micro application gets embedded into the Macro application page. The second factor is the script tag that links to the Micro application client script. You should notice that the script element is defined with the type of "module". The client script will execute when loaded into the Macro application, find the mount point identified by the unique id and embed the Micro application within that element.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>MEF with Angular</title>
</head>
<body>
<div id="mef-test-newername"></div>
<script type="module" src="/mef-test-newername-client.js"></script>
</body>
</html>
MEF uses a configuration file which can be either mef.config.js or mef.config.json, to declare build and dev server properties. There are several properties that can be used to manipulate the projects build and dev server runtime. Some properties are specific to how you have created your project, based on the framework of choice. Others are optional but can be set if the default values are not warrented. The table below lists the available configuration properties and their usage.
prperty |
type | default | required | description |
---|---|---|---|---|
entry | string | none | true | this should be a string that represents a relative path to the entry point file in the src folder ex: "/src/index.js" |
name | string | none | false | this can be used to override the package name property and will be used for all asset naming and references wuse with the dev server index.html |
host | string | none | true | when hosting your production files this is the host name used to retrieve the files during mounting of the Micro application ex: "www.dell.com" |
path | string | none | false | when hosting your production files this represent the URL path used for the folder location appened to the host ex: "/path/to/files" |
port | number | 80 | false | when hosting your prodcution files this represents the port used with the host to retreive your files. This only needs to be changed if files are not on port 80 |
dev: host | string | localhost | false | host name used when running the development server. This only needs to be changed if localhost needs to be changed otherwise not required |
dev: port | number | 3000 | false | port used when running the development derver. This only needs to be changed if the port is in use otherwise not required |
dev: watch | boolean | false | false | boolean flag to turn on the chokidar file watcher when running development server. This uses a regular expressions to ignore certain project files and folders that should not restart the server |
dev: open | boolean | false | false | boolean flag used to open the development server in your configured default browser |
html: entry | array | none | false | an array used for listing supporting HTML files that are rendered for the project ex: ["/src/root.html"]. When using more than one file, place them in the order they should be rendered with in the DOM. |
plugins | array | none | false | an array of plugins that can be used with the vite build. These can be any valid vite or rollup plugins ex: [react()] |
external: entry | array | none | false | an array indicating what should be externalized for the framework ex: ["react", "react-dom"] |
external: gloabls | object | none | false | an object paired with external: entry used to define the global names when exteranlizing a framework ex: {'react': 'React', 'react-dom': 'ReactDOM'} |
The following sections will describe the remaining needed steps to complete the installation to support the added package.json scripts of mef:dev and mef:build.
- Vanilla JavaScript and Typescript Projects
- React Javascript and Typescript Projects
- Angular Typescript Projects
For Vanilla projects there can be the setup decision to use either a template of JavaScript or Typescript. Based on the decision the following sections describe how to finalize the setup for the MEF installation.
Use the following steps finalize the setup for the Vanilla JavaScript MEF project.
- create folder under root called "src"
- create a file in src called "index.js" <- this will be the build entry point in the MEF configuration and where all js and scss/css are imported
- create a file in src called either style.scss or style.css file <- scss files will be compiled to css or can just use css
- import the style.scss or style.css file in the index.js file
- create a file in src called "root.html" <- this is where all html elements for the Micro application will be placed. This should be added to the MEF configurations html - entry property @see Configuration
Example MEF configuration
{
"entry": "/src/index.js",
"name": "mef-vanilla",
"host": "dds.dell.com",
"path": "test",
"port": 80,
"dev": {
"host": "localhost",
"port": 3000,
"watch": true,
"open": true
},
"html": {
"entry": ["/src/root.html"],
}
}
Use the following steps finalize the setup for the Vanilla Typescript MEF project.
- create folder under root called "src"
- create a file in src called "index.ts" <- this is the build entry point in the MEF configuration and where all ts/js and scss/css are imported
- create a file in src called either style.scss or style.css file <- scss files will be compiled to css or can just use css
- import the style.scss or style.css file in the index.ts file
- create a file in the root folder called "tsconfig.json" <- this is the Typescript configuration file used during the build
- create a file in src called "root.html" <- this is where all html elements for the Micro application will be placed. This should be added to the MEF configurations html - entry property @see Configuration
The following is a base example tsconfig.json file that can be used as a starter file for building the project. Note comments are only added here to show how the properties are organized.
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"]
}
Example MEF configuration
{
"entry": "/src/index.ts",
"name": "mef-vanilla-ts",
"host": "dds.dell.com",
"path": "test",
"port": 80,
"dev": {
"host": "localhost",
"port": 3000,
"watch": true,
"open": true
},
"html": {
"entry": ["/src/root.html"],
}
}
For React projects there can be the setup decision to use either a template of JavaScript or Typescript. Based on the decision the following sections describe how to finalize the setup for the MEF installation.
NOTE: If you are using redux, the usual approach is to have a single, global, shared store for the entire application. However, if each Micro application is supposed to be its own self-contained application, then it makes sense for each application to have its own redux store. The redux docs even mention "isolating a Redux app as a component in a bigger application" as a valid reason to have multiple stores.
Use the following steps finalize the setup for the React JavaScript MEF project.
- create folder under root called "src"
- create a file in src called "index.jsx" <- this is the build entry point for the MEF configuration and where all jsx/js and scss/css are imported
- create a file in src called either style.scss or style.css file <- scss files will be compiled to css or can just use css
- import the style.scss or style.css file in the index.jsx file
- create a file in the src folder called "root.html" <- This is the HTML placeholder for the React root. This should be added to the MEF configurations html - entry property @see Configuration
<div id="root"></div>
Example MEF configuration
{
"entry": "/src/index.jsx",
"name": "mef-react-js",
"host": "dds.dell.com",
"path": "test",
"port": 80,
"dev": {
"host": "localhost",
"port": 3000,
"watch": true,
"open": true,
},
"html": {
"entry": ["/src/root.html"],
}
}
Use the following steps to finalize the setup for the React Typescript MEF project.
- create folder under root called "src"
- create a file in src called "index.ts" <- this is the build entry point for the MEF configuration and where all ts/js and scss/css are imported
- create a file in src called either style.scss or style.css file <- scss files will be compiled to css or can just use css
- import the style.scss or style.css file in the index.ts file
- create a file in the root folder called "tsconfig.json" <- this is the Typescript configuration file used during the build
- create a file in the src folder called "root.html" <- This is the HTML placeholder for the React root. This should be added to the MEF configurations html - entry property @see Configuration
<div id="root"></div>
The following is a base example tsconfig.json file that can be used as a starter file for building the project. Note comments are only added here to show how the properties are organized.
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}
- create a file in the root folder called "tsconfig.node.json" <- this is an extension to the Typescript configuration file used during the build
Example tsconfig.node.json file for the build.
{
"compilerOptions": {
"jsx": "react",
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
}
}
Using Angular with MEF is a little more complicated than the other previously defined installations. Angular has it's own build eco system and because of that MEF takes full advangtage of the Angular build process. When finalizing the MEF project you will notice several items that are very particular to Angular and how Angular is configured. Use the following steps to finalize the setup for the Angular Typescript MEF project.
- create folder under root called "src"
- create a file in src called "main.ts" <- this is the build entry point for the MEF configuration
- create a file in src called "app.component.ts" <- this is a standalone component that brings in all other components with in the @Component decorator
- create a file in src called "angular.json" <- this is where the Angular's configuration properties will be placed
- create a file in the root folder called "tsconfig.json" <- this is the Typescript configuration file used during the build
- create a file in the root folder called "tscoinfig.app.json" <- this is where we will define extended configuration properties for the build
- create a file in the src folder called "root.html" <- This is the HTML placeholder for the Angular app root. This should be added to the MEF configurations html - entry property @see Configuration
<app-root></app-root>
Example main.ts used to bootstrap the Micro application
import '@angular/compiler';
import 'zone.js';
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Example app.component.ts used to inject components into the app-root. NOTE: in the example below we are importing the Table Component. You can use other components in place of this as this is only an example.
import { Component } from '@angular/core';
import { TableComponent } from './table.component';
@Component({
selector: 'app-root',
standalone: true,
imports: [TableComponent],
template: '<mef-dds-table></mef-dds-table>',
})
export class AppComponent {}
Example angular.json
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"angular-ts": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "mef:build-angular",
"options": {
"outputPath": "dist/angular-ts",
"index": "index.html",
"browser": "src/main.ts",
"polyfills": [],
"tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": [],
"styles": [
"node_modules/@dds/angular/styles/dds-reboot.css",
"node_modules/@dds/angular/styles/dds-fonts.css",
"node_modules/@dds/angular/styles/dds-icons.css",
"node_modules/@dds/angular/styles/dds-helpers.css",
"node_modules/@dds/angular/lib/table/table.component.scss",
"node_modules/@dds/angular/lib/pagination/pagination.component.scss",
"node_modules/@dds/angular/lib/badge/badge.component.scss"
],
"scripts": []
},
"configurations": {
"production": {
"extractLicenses": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "2mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"optimization": {
"scripts": true,
"styles": {
"minify": true,
"inlineCritical": false
},
"fonts": true
},
"outputHashing": "none"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"buildTarget": "angular-ts:build:production"
},
"development": {
"buildTarget": "angular-ts:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"buildTarget": "angular-ts:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"polyfills": [
"zone.js",
"zone.js/testing"
],
"tsConfig": "tsconfig.spec.json",
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": []
}
}
}
}
},
"cli": {
"analytics": false
}
}
Coming soon!
Now that we have all the scaffolding in place what can we do with MEF. The following section will show how to use the Dell Design System to populate components into a MEF application. The examples will demonstrate how to instantiate a Table with Pagination. There are slight differences between each example so follow the steps for the MEF template you chose.
- We need to install the Dell Design System components. Run the following command to get the node package installed as a dev dependency.
npm install --save-dev @dds/components
or
npm i -D @dds/components
or
npm i -D @dds/components --registry=https://artifacts.dell.com/artifactory/api/npm/dx-npm-prod/
- in the src folder create a "root.html" file <- This is where all the HTML elements needed for the Table and Pagination will be placed. Note that since the MEF configuration for html - entry is an array you can create multiple HTML files, one file was used here for brevity.
<div class="dds__table" role="table" id="table-780498035"></div>
<div class="dds__pagination" data-dds="pagination" id="table-780498035-pagination" role="navigation"
aria-label="pagination-table-780498035-pagination">
<div class="dds__pagination__summary">
<label class="dds__pagination__per-page-label" for="pagination-per-page-table-780498035-pagination">Items per
page</label>
<div class="dds__select dds__select--sm dds__pagination__per-page-select" data-dds="select">
<div class="dds__select__wrapper">
<select class="dds__select__field" id="pagination-per-page-table-780498035-pagination">
<option value="6">6</option>
<option value="8">8</option>
<option value="10">10</option>
</select>
</div>
</div>
<div class="dds__pagination__range" aria-live="polite">
<span class="dds__pagination__range-start"></span>
–
<span class="dds__pagination__range-end"></span>
<span class="dds__pagination__range-total-label">
of
<span class="dds__pagination__range-total"></span>
items
</span>
</div>
</div>
<div class="dds__pagination__nav">
<button type="button"
class="dds__button dds__button--tertiary dds__button--sm dds__button__icon dds__pagination__first-page"
aria-label="First page"></button>
<button type="button" class="dds__button dds__button--tertiary dds__button--sm dds__pagination__prev-page"
aria-label="Previous page">
<span class="dds__pagination__prev-page-label">Previous</span>
</button>
<div class="dds__pagination__page-range">
<label class="dds__pagination__page-range-label"
for="pagination-current-page-table-780498035-pagination">Page</label>
<div class="dds__input-text__container dds__input-text__container--sm">
<div class="dds__input-text__wrapper dds__pagination__page-range-current-wrapper">
<input class="dds__input-text dds__pagination__page-range-current" type="text"
id="pagination-current-page-table-780498035-pagination" />
</div>
</div>
<div class="dds__pagination__page-range-total-label">
of
<span class="dds__pagination__page-range-total"></span>
</div>
</div>
<button type="button" class="dds__button dds__button--tertiary dds__button--sm dds__pagination__next-page"
aria-label="Next page">
<span class="dds__pagination__next-page-label">Next</span>
</button>
<button type="button"
class="dds__button dds__button--tertiary dds__button--sm dds__button__icon dds__pagination__last-page"
aria-label="Last page"></button>
</div>
</div>
- in the mef.config.json file update or create the html - entry property
{
...
"html": {
"entry": ["/src/root.html"],
}
...
}
- update the src/style.scss file with these entries
@import '../node_modules/@dds/components/src/scss/dds-reboot.scss';
@import '../node_modules/@dds/components/src/scss/dds-fonts.scss';
@import '../node_modules/@dds/components/src/scss/dds-icons.scss';
@import '../node_modules/@dds/components/src/scss/abstracts/helpers/screen-readers.scss';
@import '../node_modules/@dds/components/src/scss/components/shared.scss';
@import '../node_modules/@dds/components/src/components/table/table.scss';
@import '../node_modules/@dds/components/src/components/pagination/pagination.scss';
@import '../node_modules/@dds/components/src/components/button/button.scss';
@import '../node_modules/@dds/components/src/components/loading-indicator/loading-indicator.scss';
@import '../node_modules/@dds/components/src/components/select/select.scss';
- update the index.js file with these entries
import './style.scss';
import { Table, Pagination } from '../node_modules/@dds/components/esm/index.js';
const data = [
{ columns: [{ value: 750306594 }, { value: "AI/ML" }, { value: "01/04/2024" }, { value: "Pending" }] },
{ columns: [{ value: 500456052 }, { value: "Premier" }, { value: "12/09/2023" }, { value: "Pending" }] },
{ columns: [{ value: 259183092 }, { value: "DFS" }, { value: "01/09/2025" }, { value: "Pending" }] },
{ columns: [{ value: 872804693 }, { value: "UMF" }, { value: "01/09/2025" }, { value: "Blocked" }] },
{ columns: [{ value: 636758074 }, { value: "GSCM" }, { value: "01/08/2024" }, { value: "Success" }] },
{ columns: [{ value: 471679107 }, { value: "GC" }, { value: "01/09/2023" }, { value: "Blocked" }] },
{ columns: [{ value: 417989681 }, { value: "DFS" }, { value: "01/09/2024" }, { value: "Error" }] },
{ columns: [{ value: 887380249 }, { value: "DSA" }, { value: "01/08/2024" }, { value: "Warning" }] },
{ columns: [{ value: 493623344 }, { value: "GSCM" }, { value: "01/08/2024" }, { value: "Warning" }] },
{ columns: [{ value: 525435463 }, { value: "UMF" }, { value: "01/09/2024" }, { value: "Pending" }] },
{ columns: [{ value: 479211551 }, { value: "GC" }, { value: "01/10/2024" }, { value: "Success" }] },
{ columns: [{ value: 747572227 }, { value: "AI/ML" }, { value: "02/09/2024" }, { value: "Warning" }] },
{ columns: [{ value: 621797528 }, { value: "UMF" }, { value: "01/08/2024" }, { value: "Error" }] },
{ columns: [{ value: 436204614 }, { value: "Dev Ex" }, { value: "01/10/2024" }, { value: "Pending" }] },
{ columns: [{ value: 806363104 }, { value: "UMF" }, { value: "01/09/2024" }, { value: "Error" }] },
{ columns: [{ value: 872287982 }, { value: "UMF" }, { value: "01/04/2024" }, { value: "Error" }] },
{ columns: [{ value: 193177883 }, { value: "Premier" }, { value: "12/09/2023" }, { value: "Warning" }] },
{ columns: [{ value: 945818984 }, { value: "Dev Ex" }, { value: "01/09/2024" }, { value: "Warning" }] },
{ columns: [{ value: 936384308 }, { value: "APEX" }, { value: "12/09/2023" }, { value: "Error" }] },
{ columns: [{ value: 261930349 }, { value: "DSA" }, { value: "01/14/2024" }, { value: "Error" }] },
{ columns: [{ value: 881112208 }, { value: "DFS" }, { value: "01/04/2024" }, { value: "Warning" }] },
{ columns: [{ value: 926404221 }, { value: "GC" }, { value: "02/09/2024" }, { value: "Pending" }] },
{ columns: [{ value: 770799502 }, { value: "Dev Ex" }, { value: "01/04/2024" }, { value: "Success" }] },
{ columns: [{ value: 463019447 }, { value: "Premier" }, { value: "01/08/2024" }, { value: "Error" }] },
{ columns: [{ value: 609240246 }, { value: "Dev Ex" }, { value: "01/09/2025" }, { value: "Error" }] },
{ columns: [{ value: 392593581 }, { value: "UMF" }, { value: "01/08/2024" }, { value: "Success" }] },
{ columns: [{ value: 703759509 }, { value: "Dev Ex" }, { value: "02/09/2024" }, { value: "Success" }] },
{ columns: [{ value: 733966150 }, { value: "Dev Ex" }, { value: "12/09/2023" }, { value: "Pending" }] },
{ columns: [{ value: 645201382 }, { value: "AI/ML" }, { value: "01/10/2024" }, { value: "Error" }] },
{ columns: [{ value: 739047309 }, { value: "OSC" }, { value: "01/08/2024" }, { value: "Pending" }] },
{ columns: [{ value: 816325708 }, { value: "AI/ML" }, { value: "01/08/2024" }, { value: "Warning" }] },
{ columns: [{ value: 737575165 }, { value: "GC" }, { value: "01/08/2024" }, { value: "Warning" }] },
];
const columns = [{ value: "Ticket ID" }, { value: "Team" }, { value: "Date" }, { value: "Status" }];
// NOTE: that we are using document here as this is what MEF does for you and is a valid statement. If you need to gain access to the Window's document use window.document instead
const element = document.getElementById("table-780498035");
Table(element, {
data,
columns,
subscribe: ["table-780498035-pagination"],
pagination: { currentPage: 1, rowsPerPage: 4 },
});
const paginationElement = document.getElementById("table-780498035-pagination");
Pagination(paginationElement, {
subscribe: ["table-780498035"],
});
- make sure your mef.config.json entry property is correct
{
"entry": "/src/index.js",
...
},
"html": {
"entry": ["/src/root.html"],
}
}
That's it, you are all done! At this point you can run the following command to run your new MEF project.
npm run mef:dev
- We need to install the Dell Design System components for React. Run the following command to get the node package installed as dev dependency.
NOTE: At the time of writing this documentation the React Pagination component was not yet developed. The examples below will be just demonstrating the MEF project with the Table component only.
npm install --save-dev @dds/react
or
npm i -D @dds/react
or
npm i -D @dds/react --registry=https://artifacts.dell.com/artifactory/api/npm/dx-npm-prod/
- in the src folder create a "table.jsx" file <- This is where the configuration needed for the Table will be placed.
import { DDSTable } from "@dds/react";
export default function Table() {
return (
<DDSTable
columns={[{ value: "Ticket ID" }, { value: "Team" }, { value: "Date" }, { value: "Status" }]}
data={[
{ columns: [{ value: 750306594 }, { value: "AI/ML" }, { value: "01/04/2024" }, { value: "Pending" }] },
{ columns: [{ value: 500456052 }, { value: "Premier" }, { value: "12/09/2023" }, { value: "Pending" }] },
{ columns: [{ value: 259183092 }, { value: "DFS" }, { value: "01/09/2025" }, { value: "Pending" }] },
{ columns: [{ value: 872804693 }, { value: "UMF" }, { value: "01/09/2025" }, { value: "Blocked" }] },
{ columns: [{ value: 636758074 }, { value: "GSCM" }, { value: "01/08/2024" }, { value: "Success" }] },
{ columns: [{ value: 471679107 }, { value: "GC" }, { value: "01/09/2023" }, { value: "Blocked" }] },
{ columns: [{ value: 417989681 }, { value: "DFS" }, { value: "01/09/2024" }, { value: "Error" }] },
{ columns: [{ value: 887380249 }, { value: "DSA" }, { value: "01/08/2024" }, { value: "Warning" }] },
{ columns: [{ value: 493623344 }, { value: "GSCM" }, { value: "01/08/2024" }, { value: "Warning" }] },
{ columns: [{ value: 525435463 }, { value: "UMF" }, { value: "01/09/2024" }, { value: "Pending" }] },
{ columns: [{ value: 479211551 }, { value: "GC" }, { value: "01/10/2024" }, { value: "Success" }] },
{ columns: [{ value: 747572227 }, { value: "AI/ML" }, { value: "02/09/2024" }, { value: "Warning" }] },
{ columns: [{ value: 621797528 }, { value: "UMF" }, { value: "01/08/2024" }, { value: "Error" }] },
{ columns: [{ value: 436204614 }, { value: "Dev Ex" }, { value: "01/10/2024" }, { value: "Pending" }] },
{ columns: [{ value: 806363104 }, { value: "UMF" }, { value: "01/09/2024" }, { value: "Error" }] },
{ columns: [{ value: 872287982 }, { value: "UMF" }, { value: "01/04/2024" }, { value: "Error" }] },
{ columns: [{ value: 193177883 }, { value: "Premier" }, { value: "12/09/2023" }, { value: "Warning" }] },
{ columns: [{ value: 945818984 }, { value: "Dev Ex" }, { value: "01/09/2024" }, { value: "Warning" }] },
{ columns: [{ value: 936384308 }, { value: "APEX" }, { value: "12/09/2023" }, { value: "Error" }] },
{ columns: [{ value: 261930349 }, { value: "DSA" }, { value: "01/14/2024" }, { value: "Error" }] },
{ columns: [{ value: 881112208 }, { value: "DFS" }, { value: "01/04/2024" }, { value: "Warning" }] },
{ columns: [{ value: 926404221 }, { value: "GC" }, { value: "02/09/2024" }, { value: "Pending" }] },
{ columns: [{ value: 770799502 }, { value: "Dev Ex" }, { value: "01/04/2024" }, { value: "Success" }] },
{ columns: [{ value: 463019447 }, { value: "Premier" }, { value: "01/08/2024" }, { value: "Error" }] },
{ columns: [{ value: 609240246 }, { value: "Dev Ex" }, { value: "01/09/2025" }, { value: "Error" }] },
{ columns: [{ value: 392593581 }, { value: "UMF" }, { value: "01/08/2024" }, { value: "Success" }] },
{ columns: [{ value: 703759509 }, { value: "Dev Ex" }, { value: "02/09/2024" }, { value: "Success" }] },
{ columns: [{ value: 733966150 }, { value: "Dev Ex" }, { value: "12/09/2023" }, { value: "Pending" }] },
{ columns: [{ value: 645201382 }, { value: "AI/ML" }, { value: "01/10/2024" }, { value: "Error" }] },
{ columns: [{ value: 739047309 }, { value: "OSC" }, { value: "01/08/2024" }, { value: "Pending" }] },
{ columns: [{ value: 816325708 }, { value: "AI/ML" }, { value: "01/08/2024" }, { value: "Warning" }] },
{ columns: [{ value: 737575165 }, { value: "GC" }, { value: "01/08/2024" }, { value: "Warning" }] },
]}
/>
);
}
- in the src folder create a "index.jsx" file
import React from 'react'
import ReactDOM from 'react-dom/client'
import Table from './table';
import "./style.scss";
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<Table />
</React.StrictMode>,
);
- in the src folder create a "root.html" file
<div id="root"></div>
- in the mef.config.js file update or create the html - entry property
export default {
...
html: {
entry: ["/src/root.html"],
}
...
}
- update the src/style.scss file with these entries
/* React (Required) */
@import "@dds/react/css/dds-components.css";
/* Foundations (Highly recommended) */
@import "@dds/react/css/dds-reboot.css";
@import "@dds/react/css/dds-fonts.css";
@import "@dds/react/css/dds-icons.css";
/* Foundations (Optional) */
@import "@dds/react/css/dds-main.css";
@import "@dds/react/css/dds-helpers.css";
- make sure your mef.config.js entry property is correct
export default {
entry: "/src/index.jsx",
...
},
html: {
entry: ["/src/root.html"],
}
}
- update the mef.config.js plugins entry
import react from '@vitejs/plugin-react'
export default {
...
plugins: [react()]
}
That's it, you are all done! At this point you can run the following command to run your new MEF project.
npm run mef:dev
Guidelines on how to contribute to the project.
Copyright 2024 Dell Technologies Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.