Micro-frontends are often referred to as "front-end microservices". They allow you to decompose a large monolithic front end into independent, extensible, independent parts that can work together. Micro front-end architecture is especially useful for complex products or companies with many teams, and can help you create consistent web applications.
Watch this video , which explains the basics of micro front-end architecture and how to implement it with Luigi.
Luigi is an open source micro front-end framework written in Svelte. It allows you to create a consistent user interface and navigation, while also providing other features to make development easier. Its appearance is based on the basic library style. Luigi has nothing to do with technology and allows you to build applications using React, Angular, UI5 or any other technology and add micro frontends to it.
Luigi Fiddle is a test playground where you can feel Luigi.
This picture depicts the basic architecture of Luigi:
Luigi terminology
This is a small part of Luigi terms:
- Luigi Core-refers to the main application in which the micro front end is displayed. It includes top and side navigation and all other settings related to the main application.
- Luigi Client-This term covers all settings related to the micro front end provided by Luigi. The micro front end can be configured through the Luigi Client API.
- parameters-Parameters are the elements used to configure the Luigi application.
- Navigation node-each link of side navigation in Luigi.
- Contexts-Contexts are Luigi parameters that allow you to pass objects to the micro frontend.
- Views-Views, another name for the micro front end.
In this series of articles, we will create an application using Luigi from scratch. It will be based on the concept of an online shopping platform and will include other features such as localization for displaying the website in English and German.
The application consists of three main parts:
- Luigi Core application built with React: the "main application", which contains the micro front end and includes top and side navigation that remains consistent no matter which sub-page of the application you navigate to.
- Micro-frontends built with React: They include a homepage, a "product" page, and a "product details" list that contains information about each product.
- A micro front end built with UI5: the "order history" page, which displays the quantity and price of purchased products.
In the end, the home page of your finished application should look like this:
Complete source code
Command line npm i create-react-app:
Then the command line: npx create-react-app react-core-mf
Install dependencies
If you haven’t already done so, make sure you install SAP Fonts.
Go to core app: cd react-core-mf
Installation dependencies:
npm i -P @luigi-project/core @luigi-project/client fundamental-styles fundamental-react @sap-theming/theming-base-content react-router-dom
npm i copy-webpack-plugin webpack webpack-cli @babel/core @babel/preset-env babel-loader --save-dev
Create UI5 micro-frontend
Create a ui5-mf folder:
Create a ui5 project from the command line:
npm install -g yo generator-easy-ui5
Add a file with product data
In this step, you will create a file that contains information about the products on sale in your shopping app.
In the actual project implementation, these data will be provided by the database. But for simplicity, you will create dummy data in a .json file. This file will be used by the main application and the micro front end.
Navigate to ui5-mf/uimodule/webapp/model and create a products.json file with the following content:
{
"ProductCollection": [{
"id": 101,
"name": "Logitech Mouse",
"price": 45.0,
"stock": 80,
"icon": "product",
"currencyCode": "EUR",
"orderQuantity": 2,
"description": "LIGHTSPEED Wireless Gaming Mouse with HERO Sensor"
},
{
"id": 102,
"name": "Logitech Keyboard",
"price": 50.0,
"stock": 22,
"icon": "product",
"currencyCode": "EUR",
"orderQuantity": 1,
"description": "A physical keyboard that uses an individual spring and switch for each key. Today, only premium keyboards are built with key switches; however, they were also used in the past, such as in the Model M keyboard from IBM, which used buckling spring switches"
},
{
"id": 103,
"name": "HP Optical Mouse",
"price": 35.0,
"stock": 4,
"icon": "product",
"currencyCode": "EUR",
"orderQuantity": 2,
"description": "Utilizing the latest optical sensing technology, the HP USB Optical Scroll Mouse records precise motion."
},
{
"id": 104,
"name": "MacBook Pro",
"price": 1299.0,
"stock": 11,
"icon": "laptop",
"currencyCode": "EUR",
"orderQuantity": 3,
"description": "It features a touch-sensitive OLED display strip located in place of the function keys, a Touch ID sensor integrated with the power button, a butterfly mechanism keyboard similar to the MacBook, and four USB-C ports that also serve as Thunderbolt 3 ports."
},
{
"id": 105,
"name": "Magic Mouse",
"price": 40.0,
"stock": 20,
"icon": "product",
"currencyCode": "EUR",
"orderQuantity": 6,
"description": "The Magic Mouse 2 (Apple Magic Mouse 2), is a computer mouse developed and released by Apple Inc. It features a multi-touch acrylic surface for scrolling. ... The mouse features a lithium-ion rechargeable battery and Lightning connector for charging and pairing."
},
{
"id": 106,
"name": "Brother Printer",
"price": 235.0,
"stock": 24,
"icon": "fx",
"currencyCode": "EUR",
"orderQuantity": 1,
"description": "Our affordable, quality machines provide you with the optimal way to take care of all your printing needs. Shop for the right printer, all-in-one, or fax machine for your home or home office today."
},
{
"id": 107,
"name": "iPhone 11",
"price": 835.0,
"stock": 45,
"icon": "iphone",
"currencyCode": "EUR",
"orderQuantity": 8,
"description": "The iPhone 11 dimensions are 150.9mm x 75.7mm x 8.3mm (H x W x D). It weighs about 194 grams (6.84 ounces).It features a 6.1-inch all-screen LCD display and is powered by Apple new A13 bionic chip with Third-Generation Neural Engine."
},
{
"id": 108,
"name": "Google Pixel 3a",
"price": 299.0,
"stock": 54,
"icon": "desktop-mobile",
"currencyCode": "EUR",
"orderQuantity": 7,
"description": "At 5.6 inches, the Google Pixel 3a display is proportionate to the relatively small body of the phone – that is to say, it is rather small. The display is Full HD+ and OLED, with a resolution of 2220 x 1080, and because of the relatively small screen size the pixels per inch count is rather high at 441."
},
{
"id": 109,
"name": "PlayStation 4",
"price": 330.0,
"stock": 94,
"icon": "video",
"currencyCode": "EUR",
"orderQuantity": 1,
"description": "PS4 is the fourth home video game console produced by Sony Computer Entertainment and is compatible with the PlayStation 3. It was officially announced at a press conference on February 20, 2013 and launched on November 15, 2013."
},
{
"id": 110,
"name": "Dell Monitor",
"price": 630.0,
"stock": 20,
"icon": "sys-monitor",
"currencyCode": "EUR",
"orderQuantity": 3,
"description": "34'' U3419W Monitor, Display with stand Height adjustable (115 mm), tiltable (-5° to 21°), rotatable (-30° to 30°) Security slot (cable lock sold separately), anti-theft slot for locking to stand (for display). Includes: DisplayPort cable, HDMI cable, Power cable, Stand, USB 3.0 Type-A to Type-B cable, USB-C cable"
}
]
}
Prepare React app
This step prepares your development. To be able to use webpack and fully control your React application, you need to trigger the npm run eject command.
cd react-core-mf
Execute the following command line. Note that due to the way this command works, npm run eject may fail. If an error occurs, you need to commit any changes before running the command.
npm run eject
If you encounter the following error message:
solution:
- git add .
- git commit -am "Save before ejecting"
After re-executing the eject command, it succeeded:
Add Luigi to index.html
In this step, you will let Luigi take control of the index.hmtl file - the entry point for your app.
Edit the content of the react-core-mf/public/index.html file as:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Luigi</title>
<link rel="stylesheet" href="/luigi-core/luigi.css" />
</head>
<body>
<script src="/luigi-core/luigi.js"></script>
<script src="/luigi-config.js"></script>
</body>
</html>
Create micro-frontends template
In this step, you will create another HTML file that will serve as a template for React to create the React micro front end.
Go to react-core-mf/public and create a new file called app.html. Paste this code into the file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>React App</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
Configure webpack
In this step, we configure webpack and adjust dependencies to make it easier to develop and build applications.
Modify react-core-mf/config/webpack-config.js:
Add a line:
const CopyWebpackPlugin = require('copy-webpack-plugin');
Delete this line:
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
as well as:
New plugin:
new CopyWebpackPlugin(
{
patterns: [
{
context: 'public',
from: 'index.html',
to: 'index.html'
},
{
from: 'node_modules/@luigi-project/core',
to: './luigi-core'
}
]
},
{
ignore: ['.gitkeep', '**/.DS_Store', '**/Thumbs.db'],
debug: 'warning'
}
),
new HtmlWebpackPlugin(
{
inject: true,
template: __dirname + '/../public/app.html',
filename: 'app.html'
}
),
Create Luigi configuration file
In this step, you will create a Luigi configuration file. This is the central point of any Luigi application. It allows you to configure consistent navigation and many other Luigi features.
Create a new configuration file under the react-core-mf/public directory: luigi-config.js.
In real life, you can specify any name you want for the configuration file or create multiple files. The only important thing is to use the correct Luigi parameters and syntax, which will be introduced in the next step.
Configure Luigi for "Home" node
With simple parameters related to navigation and general settings, you will create your first "home" navigation node and make your application responsive.
These are the Luigi navigation parameters you will use:
- pathSegment-the text segment added to the URL
- label-the name of the node displayed in the navigation
- icon-the SAP icon displayed next to the label
- viewUrl-the URL of the micro frontend
Using the following code, you will configure the title for your page and make your application look better on mobile devices using the responseNavigation parameter:
/* eslint-disable no-undef */
Luigi.setConfig({
navigation: {
nodes: () => [
{
pathSegment: 'home',
label: 'Home',
icon: 'home',
viewUrl: '/app.html#/home'
}
]
},
settings: {
header: {
title: 'Luigi Application',
logo: '/logo.png'
},
responsiveNavigation: 'simpleMobileOnly'
}
}
);
Create "Home" view
In this step, you will use React to create your first micro front end (aka view). This is a simple "home" view with a welcome message.
Navigate to react-core-mf/src and create a folder named views.
Create a new Home.jsx file:
import React from 'react';
import { LayoutPanel } from 'fundamental-react';
export const Home = () => {
return (
<LayoutPanel>
<LayoutPanel.Body>
<h2>Welcome to Luigi - a micro-frontend framework</h2>
</LayoutPanel.Body>
</LayoutPanel>
);
}
Configure router for "Home" view
In this step, you will make changes to index.js, the entry point of the React application. You will configure the router for the "Home" view created in the previous step and import Luigi Client.
Open react-core-mf/src/index.js and change its content to:
import React, { Component } from 'react';
import { render } from 'react-dom';
import { addInitListener } from '@luigi-project/client';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import { Home } from './views/Home.jsx';
import './index.css';
class App extends Component {
constructor(props) {
super(props);
addInitListener(() => {
console.log('Luigi Client initialized.');
});
}
render() {
return (
<Router basename={`/app.html#`}>
<Route path="/home" component={Home} />
</Router>
);
}
}
render(<App />, document.getElementById('root'));
Create more views with React
In this step, you will create more React micro frontends, including product lists and product details.
Navigate to react-core-mf/src/views and create a file List.jsx with the following content:
import React from 'react';
import { MessageStrip, Avatar, LayoutPanel, LayoutGrid } from 'fundamental-react';
const NO_AVAILABLE_PRODUCT_MSG = 'Unfortunately, there is no available product at this moment.';
const panelStyle = { cursor: 'pointer' };
export const List = ({ items }) => (
(items.length === 0) ? <MessageStrip type='error'>{NO_AVAILABLE_PRODUCT_MSG}</MessageStrip>
: items.map(({id, name, price, icon, stock}) => {
return (
<LayoutPanel key={id} style={panelStyle}>
<LayoutPanel.Header>
<LayoutPanel.Head title={name} />
</LayoutPanel.Header>
<LayoutPanel.Body>
<LayoutGrid cols={2}>
<div>
<div>Price: €{price}</div>
<div>Stocks: {stock}</div>
</div>
<div><Avatar circle glyph={icon} size='s' /></div>
</LayoutGrid>
</LayoutPanel.Body>
</LayoutPanel>
)
})
);
Products.jsx:
import React from 'react';
import { List } from './List.jsx';
import { ProductCollection } from '../../../ui5-mf/uimodule/webapp/model/products.json';
import { LayoutPanel, LayoutGrid } from 'fundamental-react';
export const Products = () => (
<section className="fd-section">
<LayoutPanel>
<LayoutPanel.Header>
<h3>Items ({ProductCollection.length})</h3>
</LayoutPanel.Header>
<LayoutPanel.Body>
<LayoutGrid cols={2}>
<List items={ProductCollection} />
</LayoutGrid>
</LayoutPanel.Body>
</LayoutPanel>
</section>
);
export default Products;
Add "Products" view to Luigi app
In this step, you will add a navigation node to the "product" micro frontend in Luigi.
Edit react-core-mf/public/luigi-config.js:
Add a new "Product" node in the navigation:
navigation: {
nodes: () => [
{
pathSegment: 'home',
label: 'Home',
icon: 'home',
viewUrl: '/app.html#/home',
children: [{
pathSegment: 'products',
label: 'Products',
icon: 'list',
viewUrl: '/app.html#/products'
}]
}
]
}
Step 12: Add "Product Detail" view to Luigi app
In this step, you will add the ProductDetail.jsx view to the application. You will be able to display the detailed information of each product through the Luigi dynamic parameters, which in this example is named :id.
The content of the file luigi-config.js is:
/* eslint-disable no-undef */
Luigi.setConfig({
navigation: {
nodes: () => [
{
pathSegment: 'home',
label: 'Home',
icon: 'home',
viewUrl: '/app.html#/home',
children: [{
pathSegment: 'products',
label: 'Products',
icon: 'list',
viewUrl: '/app.html#/products'
}]
},
{
pathSegment: 'products',
label: 'Products',
icon: 'list',
viewUrl: '/app.html#/products',
keepSelectedForChildren: true,
children: [{
pathSegment: ':id',
viewUrl: '/app.html#/productDetail/:id'
}]
}
]
},
settings: {
header: {
title: 'Luigi Application',
logo: '/logo.png'
},
responsiveNavigation: 'simpleMobileOnly'
}
}
);
Step 13: Use Luigi link manager for routing
In this step, we will use Luigi to provide routing for the micro front end instead of React. The linkManager function of Luigi Client is the easiest way to navigate to the id page of each product.
More original articles by Jerry, all in: "Wang Zixi":
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。