Skip to content

Commit 5724025

Browse files
committed
use external ModuleFederation plugin
2 parents 060c4f0 + 196c37a commit 5724025

File tree

9 files changed

+300
-51
lines changed

9 files changed

+300
-51
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
},
106106
"dependencies": {
107107
"@apollo/client": "^3.2.1",
108+
"@module-federation/runtime": "^0.21.6",
108109
"classnames": "^2.2.5",
109110
"core-js": "^3.26.1",
110111
"final-form": "^4.18.2",
@@ -148,4 +149,4 @@
148149
"redux-observable": "^1.2.0",
149150
"rxjs": "^6.6.3"
150151
}
151-
}
152+
}

src/AppRoutes.js

Lines changed: 38 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Suspense, useMemo } from 'react';
1+
import React, { useMemo, Suspense } from 'react';
22
import { Route } from 'react-router-dom';
33
import PropTypes from 'prop-types';
44

@@ -12,6 +12,7 @@ import { invokeEventHandlers } from './handlerService';
1212
import { packageName } from './constants';
1313
import { ModuleHierarchyProvider } from './components';
1414
import events from './events';
15+
import loadRemoteComponent from './loadRemoteComponent';
1516

1617
// Process and cache "app" type modules and render the routes
1718
const AppRoutes = ({ modules, stripes }) => {
@@ -23,11 +24,13 @@ const AppRoutes = ({ modules, stripes }) => {
2324
const perm = `module.${name}.enabled`;
2425
if (!stripes.hasPerm(perm)) return null;
2526

27+
const RemoteComponent = React.lazy(() => loadRemoteComponent(module.url, module.name));
2628
const connect = connectFor(module.module, stripes.epics, stripes.logger);
2729

2830
let ModuleComponent;
31+
2932
try {
30-
ModuleComponent = connect(module.getModule());
33+
ModuleComponent = connect(RemoteComponent);
3134
} catch (error) {
3235
console.error(error); // eslint-disable-line
3336
throw Error(error);
@@ -48,39 +51,41 @@ const AppRoutes = ({ modules, stripes }) => {
4851
}, [modules.app, stripes]);
4952

5053
return cachedModules.map(({ ModuleComponent, connect, module, name, moduleStripes, stripes: propsStripes, displayName }) => (
51-
<Route
52-
path={module.route}
53-
key={module.route}
54-
render={props => {
55-
const data = { displayName, name };
54+
<Suspense fallback={<LoadingView />}>
55+
<Route
56+
path={module.route}
57+
key={module.route}
58+
render={props => {
59+
const data = { displayName, name };
5660

57-
// allow SELECT_MODULE handlers to intervene
58-
const handlerComponents = invokeEventHandlers(events.SELECT_MODULE, moduleStripes, modules.handler, data);
59-
if (handlerComponents.length) {
60-
return handlerComponents.map(Handler => (<Handler stripes={propsStripes} data={data} />));
61-
}
61+
// allow SELECT_MODULE handlers to intervene
62+
const handlerComponents = invokeEventHandlers(events.SELECT_MODULE, moduleStripes, modules.handler, data);
63+
if (handlerComponents.length) {
64+
return handlerComponents.map(Handler => (<Handler stripes={propsStripes} data={data} />));
65+
}
6266

63-
return (
64-
<StripesContext.Provider value={moduleStripes}>
65-
<ModuleHierarchyProvider module={module.module}>
66-
<div id={`${name}-module-display`} data-module={module.module} data-version={module.version}>
67-
<RouteErrorBoundary
68-
escapeRoute={module.home ?? module.route}
69-
moduleName={displayName}
70-
stripes={moduleStripes}
71-
>
72-
<TitleManager page={displayName}>
73-
<Suspense fallback={<LoadingView />}>
74-
<ModuleComponent {...props} connect={connect} stripes={moduleStripes} actAs="app" />
75-
</Suspense>
76-
</TitleManager>
77-
</RouteErrorBoundary>
78-
</div>
79-
</ModuleHierarchyProvider>
80-
</StripesContext.Provider>
81-
);
82-
}}
83-
/>
67+
return (
68+
<StripesContext.Provider value={moduleStripes}>
69+
<ModuleHierarchyProvider module={module.module}>
70+
<div id={`${name}-module-display`} data-module={module.module} data-version={module.version}>
71+
<RouteErrorBoundary
72+
escapeRoute={module.home ?? module.route}
73+
moduleName={displayName}
74+
stripes={moduleStripes}
75+
>
76+
<TitleManager page={displayName}>
77+
<Suspense fallback={<LoadingView />}>
78+
<ModuleComponent {...props} connect={connect} stripes={moduleStripes} actAs="app" />
79+
</Suspense>
80+
</TitleManager>
81+
</RouteErrorBoundary>
82+
</div>
83+
</ModuleHierarchyProvider>
84+
</StripesContext.Provider>
85+
);
86+
}}
87+
/>
88+
</Suspense>
8489
));
8590
};
8691

src/RootWithIntl.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import {
1818
MainContainer,
1919
MainNav,
2020
ModuleContainer,
21-
ModuleTranslator,
2221
TitledRoute,
2322
Front,
2423
OIDCRedirect,
@@ -202,8 +201,8 @@ const RootWithIntl = ({ stripes, token = '', isAuthenticated = false, disableAut
202201
</TitleManager>
203202
</EntitlementLoader>
204203
</ModuleTranslator>
205-
</CalloutContext.Provider>
206-
</StripesContext.Provider>
204+
</CalloutContext.Provider >
205+
</StripesContext.Provider >
207206
);
208207
};
209208

src/components/EntitlementLoader.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { useEffect, useState, useMemo } from 'react';
22
import PropTypes from 'prop-types';
33
import { useStripes } from '../StripesContext';
44
import { ModulesContext, useModules, modulesInitialState } from '../ModulesContext';
5-
import loadRemoteComponent from '../loadRemoteComponent';
65
import { loadEntitlement } from './loadEntitlement';
76

87
/**
@@ -23,7 +22,7 @@ export const preloadModules = async (stripes, remotes) => {
2322
const loaderArray = [];
2423
remotes.forEach(remote => {
2524
const { name, location } = remote;
26-
loaderArray.push(loadRemoteComponent(location, name)
25+
loaderArray.push(loadRemote(name)
2726
.then((module) => {
2827
remote.getModule = () => module.default;
2928
})
@@ -172,6 +171,14 @@ const EntitlementLoader = ({ children }) => {
172171
const controller = new AbortController();
173172
const signal = controller.signal;
174173
if (okapi?.discoveryUrl) {
174+
// ENABLE MOD FED DEBUGGING
175+
localStorage.setItem('FEDERATION_DEBUG', 'true');
176+
177+
const fetchMFStats = async () => {
178+
const stats = await fetch(`${location.protocol}//${location.host}/mf-stats.json`).then((response) => response.json());
179+
stripes.logger.log('core', 'Module Federation Stats:', stats);
180+
};
181+
175182
// fetches the list of registered apps/metadata,
176183
// loads icons and translations, then module code,
177184
// ultimately stores the result in the modules state to pass down into the modules context.
@@ -195,6 +202,11 @@ const EntitlementLoader = ({ children }) => {
195202
handleRemoteModuleError(stripes, `Error loading remote module assets (icons, translations, sounds): ${e}`);
196203
}
197204

205+
const remotesToRegister = remotes.map(remote => ({
206+
name: remote.name, entry: remote.entry
207+
}));
208+
registerRemotes(remotesToRegister);
209+
198210
try {
199211
// load module code - this loads each module only once and up `getModule` so that it can be used sychronously.
200212
cachedModules = await preloadModules(stripes, remotesWithLoadedAssets);
@@ -205,6 +217,7 @@ const EntitlementLoader = ({ children }) => {
205217
setRemoteModules(cachedModules);
206218
}
207219
};
220+
fetchMFStats();
208221
fetchRegistry();
209222
}
210223
return () => {

src/components/EntitlementLoader.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { okapi } from 'stripes-config';
44
import EntitlementLoader, { preloadModules, loadModuleAssets } from './EntitlementLoader';
55
import { StripesContext } from '../StripesContext';
66
import { ModulesContext, useModules, modulesInitialState as mockModuleInitialState } from '../ModulesContext';
7-
import loadRemoteComponent from '../loadRemoteComponent';
7+
import { loadRemote, registerRemotes } from '@module-federation/runtime';
88
import { loadEntitlement } from './loadEntitlement';
99

1010
jest.mock('stripes-config');

0 commit comments

Comments
 (0)