Work in progress
This documentation is still in development.
Module Federation¶
Module Federation combines the concept of micro frontends and enhances the idea behind modules. With modules, we can develop smaller packages or solutions that can consume each other to function as a full program. Those modules get built and bundled in a somewhat precompiled solution, but with Module Federation, we allow modules to be consumed at runtime instead.
Concept of Micro Frontends in Module Federation
Module Federation, introduced in Webpack 5, enables applications to dynamically share code across different projects (or "micro-frontends") without bundling dependencies redundantly. It achieves this by allowing an app (referred to as the host) to consume code from another app (the remote), while both can share or avoid duplicating certain modules (e.g., React, utilities, or components).
More information about the concept behind Module Federation can be read in the documentation of Webpack1.
Each application (either host or remote) defines modules it wants to share (or "expose") by configuring the ModuleFederationPlugin in its Webpack configuration. These exposed modules are then dynamically accessible by other applications.
For HortiView, you want to expose your full solution as a component, making it accessible for the HortiView application. By providing the configuration parameters of the module federation, we understand what needs to be imported and what dependencies are shared. For more information about creating a module, you can follow the instructions for a React module.
Module Integration¶
Any module that will be integrated via module federation by HortiView will receive a number of properties and methods. These can be used to ensure the best possible integration of the module.
In constant development
This object will be expanded periodically.
We will likely provide a types node module in the future.
We currently pass the following object to any module:
export type DynamicComponentCustomProps = {
/*
* properties
*/
modulePermissionToken?: string;
moduleId?: string;
organizationId?: string;
basePath?: string;
currentNavigationPath?: string;
currentLanguage?: string;
currentLanguageId?: string;
commonOptions?: AllDropdownsData<CommonOption>['items'];
/*
* methods
*/
serviceBusNotification?: (
message: AlertServiceBusMessage, //currently only used for alerts
apiKey: string,
queue: string,
topic: string
) => Promise<unknown>;
navigateInHortiview?: (path: string) => void; //set
addBreadcrumbTranslation?: (
translation: {
key: string;
value: string;
},
hide?: boolean
) => void; //use key = id and value = name
showSnackbar?: (message: string, icon?: string) => void;
showMessage?: (message: SystemMessage) => void;
logEvent?: (event: AppInsightsEvent, customProperties?: AppInsightsProperties) => void;
logError?: (exception: AppInsightsException) => void;
throwError?: (message: string, code: number) => void;
/**
* @deprecated (will be removed) in the next iteration
*/
config?: RemoteComponentConfig;
alertRules?: string;
navigateTo?: (path: string) => void; // Replaced With navigateInHortiview
addMessage?: (message: SystemMessage) => void; // Replaced with showMessage
addTranslation?: (translation: { key: string; value: string }, hide?: boolean) => void; //Replaced with addBreadcrumbTranslation
addNotification?: (notification: OldAlertDto) => void; //use serviceBusNotification or showMessage instead
};
Properties¶
modulePermissionToken¶
A JWT (JSON Web Token) for access to the module API. This token can also be used to validate requests to your own backend. Please take a look at Backend Integration for more details.
moduleId¶
ID of your module
organizationId¶
ID of the farmer's organization that uses the module. This ID is essential for identifying the organization within the HortiView platform and ensuring that the module operates within the correct organizational context.
basePath¶
(URL-)Path where your module will be embedded (used for routing purposes)
currentNavigationPath¶
(URL-)Path of your current route (used for routing purposes)
sourcePath¶
URL of the Entry-File of your module
config¶
Object of config-parameters of your module:
deprecated
Will be removed in the near future - please use your own configuration and the moduleId
to access the needed values.
export type RemoteComponentConfig = {
isBaseModule?: boolean;
/**
* The relative path to the shared module, e.g. ./MyModule
*/
module: string;
/**
* The path to the remote container entry. The url were the app is running or the path to location of the remote js file, e.g. http://localhost:3001/remoteEntry.js
*/
path: string;
/**
* name of the remote app, like sprayingbook
*/
scope: string;
/**
* name of the module
*/
name?: string;
/**
* name of the icon
*/
icon?: string;
/**
* if the module has an error
*/
error?: boolean;
/**
* the short name of the module
*/
shortName: string;
/**
* the id of the module - used as alias
*/
id: string;
};
currentLanguage¶
The i18next language key representing the current user's (farmer's) language. This key will update when the user switches languages.
currentLanguageId¶
The internal GUID of the current language (to match an available language ID of the commonOptions).
commonOptions¶
Object of common options for the module (e.g. for a module that provides a common option dropdown):
{
"AlertCriteriaName": [
{
"id": "cd623c33-a96d-4a33-be43-df981a909d2a",
"value": "Disease",
"description": "",
"key": "",
"parent": null,
"icon": null
},
...
],
"Category": [...],
"Country": [...],
...
}
Methods¶
navigateInHortiview¶
will be renamed soon
This property will be renamed to navigateInHortiview in the next iteration. Function to trigger the navigation of the HV Platform's router. If you use the React Template, do not use this function directly. Instead, use the useNavigation
hook, which is explained in Routing in a Module.
addBreadcrumbTranslation¶
Can be used to add translations to the HV Platform's translation service (i18n). For example, it should be used to provide names for route translations. Take a look at the implementation of proper internationalization in HortiView.
showSnackbar¶
Rise a toast in the platforms snackbar (e.g. after an sucessfully executed action).
showMessage¶
Create a message within HortiView, that can be seen in the notification bar of the platform.
logEvent¶
Log an event in the Application Insights.
logError¶
Log an error in the Application Insights.
throwError¶
Raise an error dialog (via the platform). See Error Handling.
serviceBusNotification¶
Add an alert or notification to the service bus, that will rise a notification within HortiView, based on configured alerts.
Alerts Required
Users need to configure an alert within the alertmanagement.
Local Debugging¶
Still in development
The integration of modules will be enhanced from time to time.
This feature will probably be part of the module creation process in the future.
Due to the ability to embed modules at runtime, you can test your modules in the test environment before uploading them. This allows you to test the full integration process of your module.
The module will be integrated as a real module would be, giving you access to a modulePermissionToken
and, derived from that, the farmer's organization details via the Module API. You can find a local debug module in the marketplace:
If you use our base template, you just need to run yarn start:dev
and you are good to go. If you use your own implementation of module federation, you need to run your module with a module configuration similar to this one:
new ModuleFederationPlugin({
name: "localDebug",
filename: "remoteEntry.js",
exposes: {
"./LocalDebug": "./src/App/RemoteModule"
}
}),
It is important that your module is built with a module federation component './LocalDebug', a scope name of 'localDebug', and an entry filename of 'remoteEntry.js'.
Test Environment
This might not work in the production environment due to some CORS restrictions.
After running your module, you should be able to open the Local Debug Module in the HV Platform and see your module: