À l’heure du numérique, la forme d’une application Web devient de plus en plus grande et sophistiquée, de sorte qu’elle doit souvent être gérée par plusieurs équipes. Votre application Web peut avoir des fonctionnalités développées par différentes équipes et il est parfois préférable de ne publier que certaines fonctionnalités en production avant de livrer l’intégralité de l’application Web.
La plupart de ces applications sophistiquées vivent du côté client, ce qui rend leur maintenance plus difficile. Avec une grande application Web monolithique, il y a aussi d’autres problèmes. Cependant, à mesure que les applications deviennent plus complexes au fil du temps, nécessitant une évolutivité à la volée et une réactivité élevée, une conception de micro-frontend basée sur des composants angulaires devient de plus en plus efficace pour répondre à ces exigences.
Micro Frontend est un concept qui considère un site Web ou une application Web comme un ensemble de fonctionnalités contrôlées par des équipes distinctes. Chaque équipe est dédiée et spécialisée dans un domaine d’activité ou un objectif spécifique. Une telle équipe interfonctionnelle crée des fonctionnalités de haut en bas, du serveur à l’interface utilisateur.
Avantages de l’architecture micro frontend
Automatisation du pipeline CI/CD : étant donné que chaque application s’intègre et se déploie indépendamment, elle simplifie le pipeline CI/CD. Parce que toutes les fonctionnalités sont séparées, vous n’avez pas à vous soucier de l’ensemble du programme lors de l’introduction d’une nouvelle fonctionnalité. S’il y a une petite erreur avec le code dans un module, le pipeline CI/CD interrompra tout le processus de génération.
Flexibilité de l’équipe : De nombreuses équipes peuvent ajouter de la valeur à plusieurs systèmes tout en travaillant séparément.
Responsabilité unique : Une telle approche permet à chaque équipe de construire des composants avec une seule responsabilité. Chaque équipe Micro Frontend se concentre à 100% sur la fonctionnalité de son Micro Frontend.
Réutilisabilité : Vous pourrez utiliser le code à plusieurs endroits. Un module créé et livré peut être réutilisé par plusieurs équipes.
Agnosticisme technologique : L’architecture Micro Frontend est indépendante de la technologie. Vous pouvez utiliser des composants de différents frameworks de développement Web (React, Vue, Angular, etc.).
Apprentissage simple : Les modules plus petits sont plus faciles à apprendre et à comprendre pour les nouveaux développeurs entrant dans les équipes, qu’une architecture monolithique avec une énorme structure de code.
Commencer
Nous avons une architecture micro frontend affichée dans l’image ci-dessous :
Noter: Dans notre article, chaque partie est une application Web Angular séparée et doit être déployée indépendamment.
Fédération des modules d’en-tête et de pied de page
Cette partie contient au moins 2 composants prêts à être exportés depuis ce module :
Tout d’abord, nous devons créer une nouvelle application et configurer un constructeur angulaire personnalisé (ce constructeur nous permet d’utiliser des configurations Webpack personnalisées)
``` ng new layout npm i --save-dev ngx-build-plus ```
Nous devons maintenant créer les fichiers webpack.config.js et webpack.prod.config.js à la racine de notre application.
// webpack.config.js
const webpack = require("webpack");
const ModuleFederationPlugin =require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
output: {
publicPath: "http://localhost:4205/",
uniqueName: "layout",
},
optimization: {
runtimeChunk: false,
},
plugins: [
new ModuleFederationPlugin({
name: "layout",
library: { type: "var", name: "layout" },
filename: "remoteEntry.js",
exposes: {
Header: './src/app/modules/layout/header/header.component.ts',
Footer: './src/app/modules/layout/footer/footer.component.ts'
},
shared: {
"@angular/core": { singleton: true, requiredVersion:'auto' },
"@angular/common": { singleton: true, requiredVersion:'auto' },
"@angular/router": { singleton: true, requiredVersion:'auto' },
},
}),
],
};
// webpack.prod.config.js
module.exports = require("./webpack.config");
La fédération de modules nous permet de partager des packages npm communs entre différentes interfaces, ce qui réduira la charge utile des canaux chargés paresseux. Nous pouvons configurer la version minimale requise, deux versions ou plus sont autorisées pour un package, etc. Plus de détails sur les options de plug-in possibles sont ici.
Noter: Nous avons une section exposée, nous pouvons donc définir ici les éléments que nous devons autoriser à exporter depuis notre application micro-frontend. Dans notre cas, nous n’exportons que 2 composants.
Après cela, nous devons ajouter un fichier de configuration personnalisé dans angular.json et changer le constructeur par défaut en ngx-build-plus :
{
...
"projects": {
"layout": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
},
"@schematics/angular:application": {
"strict": true
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "ngx-build-plus:browser",
"options": {
"outputPath": "dist/layout",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": [],
"extraWebpackConfig": "webpack.config.js"
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"extraWebpackConfig": "webpack.prod.config.js",
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"outputHashing": "all"
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "ngx-build-plus:dev-server",
"configurations": {
"production": {
"browserTarget": "layout:build:production"
},
"development": {
"browserTarget": "layout:build:development",
"extraWebpackConfig": "webpack.config.js",
"port": 4205
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "layout:build"
}
},
"test": {
"builder": "ngx-build-plus:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": [],
"extraWebpackConfig": "webpack.config.js"
}
}
}
}
},
"defaultProject": "layout"
}
Page d’inscription Fédération de modules
Cette application Web contiendra toute la logique de la page de connexion/inscription. Le flux principal est presque le même, nous devons créer une nouvelle application et installer un générateur personnalisé pour utiliser des configurations Webpack personnalisées.
``` ng new registerPage npm i --save-dev ngx-build-plus ```
Après cela, nous devons créer webpack.config.js et webpack.prod.config.js
// webpack.config.js
const webpack = require("webpack");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
output: {
publicPath: "http://localhost:4201/",
uniqueName: "register",
},
optimization: {
runtimeChunk: false,
},
plugins: [
new ModuleFederationPlugin({
name: "register",
library: { type: "var", name: "register" },
filename: "remoteEntry.js",
exposes: {
RegisterPageModule:
"./src/app/modules/register/register-page.module.ts",
},
shared: {
"@angular/core": { singleton: true, requiredVersion: 'auto' },
"@angular/common": { singleton: true, requiredVersion: 'auto' },
"@angular/router": { singleton: true, requiredVersion: 'auto' },
},
}),
],
};
// webpack.prod.config.js
module.exports = require("./webpack.config");
Comme vous pouvez le voir, ici, nous exportons uniquement RegisterPageModule. Ce module que nous pouvons utiliser est comme un module chargé paresseux dans notre application shell. En outre, nous devons changer le constructeur par défaut en ngx-build-plus et ajouter des configurations de pack Web dans le fichier JSON angulaire (comme nous l’avons fait pour le module Header & Footer auparavant).
Fédération des modules de tableau de bord
Ce module présente quelques données pour un utilisateur autorisé. La même approche que pour la page d’inscription, mais avec des configurations Webpack personnelles :
// webpack.config.js
const webpack = require("webpack");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
output: {
publicPath: "http://localhost:4204/",
uniqueName: "dashboard",
},
optimization: {
runtimeChunk: false,
},
plugins: [
new ModuleFederationPlugin({
name: "dashboard",
library: { type: "var", name: "dashboard" },
filename: "remoteEntry.js",
exposes: {
DashboardModule:
"./src/app/modules/dashboard/dashboard.module.ts",
},
shared: {
"@angular/core": { singleton: true, requiredVersion:'auto' },
"@angular/common": { singleton: true, requiredVersion:'auto' },
"@angular/router": { singleton: true, requiredVersion:'auto' },
},
}),
],
};
Fédération de module d’application Shell
Application principale qui charge tous les modules micro frontaux séparés dans une seule application. Comme avant, nous créons une nouvelle application avec un constructeur angulaire personnalisé :
``` ng new shell npm i --save-dev ngx-build-plus ```
Ajoutez des configurations de pack Web personnalisées :
// webpack.config.js
const webpack = require("webpack");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
output: {
publicPath: "http://localhost:4200/",
uniqueName: "shell",
},
optimization: {
runtimeChunk: false,
},
plugins: [
new ModuleFederationPlugin({
shared: {
"@angular/core": { eager: true, singleton: true },
"@angular/common": { eager: true, singleton: true },
"@angular/router": { eager: true, singleton: true },
},
}),
],
};
Mais avant, nous devons configurer la configuration du pack Web avec le générateur personnalisé dans le fichier angular.json.
Dans environnement/environment.ts, nous déclarons toutes les configurations de module (pour la version prod, nous devons remplacer l’adresse localhost par l’adresse publique déployée) :
export const environment = {
production: false,
microfrontends: {
dashboard: {
remoteEntry:...