Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

STRIPES-861: Setup module federation #1303

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
10 changes: 10 additions & 0 deletions bootstrap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import 'core-js/stable';
import 'regenerator-runtime/runtime';
import React from 'react';
import { createRoot } from 'react-dom/client';

import App from './src/App';

const container = document.getElementById('root');
const root = createRoot(container);
root.render(<App />);
1 change: 0 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ export { supportedNumberingSystems } from './src/loginServices';
export { userLocaleConfig } from './src/loginServices';
export * from './src/consortiaServices';
export { default as queryLimit } from './src/queryLimit';
export { default as init } from './src/init';

/* localforage wrappers hide the session key */
export { getOkapiSession, getTokenExpiry, setTokenExpiry } from './src/loginServices';
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
},
"dependencies": {
"@apollo/client": "^3.2.1",
"@folio/stripes-shared-context": "^1.0.0",
"classnames": "^2.2.5",
"core-js": "^3.26.1",
"final-form": "^4.18.2",
Expand Down
68 changes: 37 additions & 31 deletions src/AppRoutes.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, { useMemo } from 'react';
import React, { useMemo, Suspense } from 'react';
import { Route } from 'react-router-dom';
import PropTypes from 'prop-types';

import { connectFor } from '@folio/stripes-connect';
import { LoadingView } from '@folio/stripes-components';

import { StripesContext } from './StripesContext';
import TitleManager from './components/TitleManager';
Expand All @@ -11,6 +12,7 @@ import { getEventHandlers } from './handlerService';
import { packageName } from './constants';
import { ModuleHierarchyProvider } from './components';
import events from './events';
import loadRemoteComponent from './loadRemoteComponent';

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

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

let ModuleComponent;

try {
ModuleComponent = connect(module.getModule());
ModuleComponent = connect(RemoteComponent);
} catch (error) {
console.error(error); // eslint-disable-line
throw Error(error);
Expand All @@ -47,37 +51,39 @@ const AppRoutes = ({ modules, stripes }) => {
}, [modules.app, stripes]);

return cachedModules.map(({ ModuleComponent, connect, module, name, moduleStripes, stripes: propsStripes, displayName }) => (
<Route
path={module.route}
key={module.route}
render={props => {
const data = { displayName, name };
<Suspense fallback={<LoadingView />}>
<Route
path={module.route}
key={module.route}
render={props => {
const data = { displayName, name };

// allow SELECT_MODULE handlers to intervene
const handlerComponents = getEventHandlers(events.SELECT_MODULE, moduleStripes, modules.handler, data);
if (handlerComponents.length) {
return handlerComponents.map(Handler => (<Handler stripes={propsStripes} data={data} />));
}
// allow SELECT_MODULE handlers to intervene
const handlerComponents = getEventHandlers(events.SELECT_MODULE, moduleStripes, modules.handler, data);
if (handlerComponents.length) {
return handlerComponents.map(Handler => (<Handler stripes={propsStripes} data={data} />));
}

return (
<StripesContext.Provider value={moduleStripes}>
<ModuleHierarchyProvider module={module.module}>
<div id={`${name}-module-display`} data-module={module.module} data-version={module.version}>
<RouteErrorBoundary
escapeRoute={module.home ?? module.route}
moduleName={displayName}
stripes={moduleStripes}
>
<TitleManager page={displayName}>
<ModuleComponent {...props} connect={connect} stripes={moduleStripes} actAs="app" />
</TitleManager>
</RouteErrorBoundary>
</div>
</ModuleHierarchyProvider>
</StripesContext.Provider>
);
}}
/>
return (
<StripesContext.Provider value={moduleStripes}>
<ModuleHierarchyProvider module={module.module}>
<div id={`${name}-module-display`} data-module={module.module} data-version={module.version}>
<RouteErrorBoundary
escapeRoute={module.home ?? module.route}
moduleName={displayName}
stripes={moduleStripes}
>
<TitleManager page={displayName}>
<ModuleComponent {...props} connect={connect} stripes={moduleStripes} actAs="app" />
</TitleManager>
</RouteErrorBoundary>
</div>
</ModuleHierarchyProvider>
</StripesContext.Provider>
);
}}
/>
</Suspense>
));
};

Expand Down
4 changes: 3 additions & 1 deletion src/CalloutContext.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React, { useContext } from 'react';

export const CalloutContext = React.createContext();
import { CalloutContext } from '@folio/stripes-shared-context';

export { CalloutContext };

export const useCallout = () => {
return useContext(CalloutContext);
Expand Down
6 changes: 1 addition & 5 deletions src/ModuleRoutes.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,7 @@ function ModuleRoutes({ stripes }) {
);
}

return (
<Suspense fallback={<LoadingView />}>
<AppRoutes modules={modules} stripes={stripes} />
</Suspense>
);
return <AppRoutes modules={modules} stripes={stripes} />;
}}
</ModulesContext.Consumer>
);
Expand Down
7 changes: 3 additions & 4 deletions src/ModulesContext.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { useContext } from 'react';
import { modules } from 'stripes-config';
import { useContext } from 'react';
import { ModulesContext } from '@folio/stripes-shared-context';

export const ModulesContext = React.createContext(modules);
export { ModulesContext };
export default ModulesContext;
export const useModules = () => useContext(ModulesContext);
export { modules as originalModules };
18 changes: 13 additions & 5 deletions src/Pluggable.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import React, { useMemo } from 'react';
import React, { useMemo, Suspense } from 'react';
import PropTypes from 'prop-types';
import { modules } from 'stripes-config';

import { Icon } from '@folio/stripes-components';

import { useModules } from './ModulesContext';
import { withStripes } from './StripesContext';
import { ModuleHierarchyProvider } from './components';
import loadRemoteComponent from './loadRemoteComponent';

const Pluggable = (props) => {
const modules = useModules();
const plugins = modules.plugin || [];
const cachedPlugins = useMemo(() => {
const cached = [];
Expand All @@ -22,7 +27,8 @@ const Pluggable = (props) => {
}

if (best) {
const Child = props.stripes.connect(best.getModule());
const RemoteComponent = React.lazy(() => loadRemoteComponent(best.url, best.name));
const Child = props.stripes.connect(RemoteComponent);

cached.push({
Child,
Expand All @@ -32,12 +38,14 @@ const Pluggable = (props) => {
}

return cached;
}, [plugins]);
}, [plugins, props.type]);

if (cachedPlugins.length) {
return cachedPlugins.map(({ plugin, Child }) => (
<ModuleHierarchyProvider module={plugin} key={plugin}>
<Child {...props} actAs="plugin" />
<Suspense fallback={<Icon icon="spinner-ellipsis" />}>
<Child {...props} actAs="plugin" />
</Suspense>
</ModuleHierarchyProvider>
));
}
Expand Down
6 changes: 3 additions & 3 deletions src/RootWithIntl.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {
MainContainer,
MainNav,
ModuleContainer,
ModuleTranslator,
TitledRoute,
Front,
OIDCRedirect,
Expand All @@ -40,6 +39,7 @@ import StaleBundleWarning from './components/StaleBundleWarning';
import { StripesContext } from './StripesContext';
import { CalloutContext } from './CalloutContext';
import AuthnLogin from './components/AuthnLogin';
import RegistryLoader from './components/RegistryLoader';

const RootWithIntl = ({ stripes, token = '', isAuthenticated = false, disableAuth, history = {}, queryClient }) => {
const connect = connectFor('@folio/core', stripes.epics, stripes.logger);
Expand All @@ -53,7 +53,7 @@ const RootWithIntl = ({ stripes, token = '', isAuthenticated = false, disableAut
return (
<StripesContext.Provider value={connectedStripes}>
<CalloutContext.Provider value={callout}>
<ModuleTranslator>
<RegistryLoader stripes={connectedStripes}>
<TitleManager>
<HotKeys
keyMap={connectedStripes.bindings}
Expand Down Expand Up @@ -176,7 +176,7 @@ const RootWithIntl = ({ stripes, token = '', isAuthenticated = false, disableAut
</Provider>
</HotKeys>
</TitleManager>
</ModuleTranslator>
</RegistryLoader>
</CalloutContext.Provider>
</StripesContext.Provider>
);
Expand Down
4 changes: 3 additions & 1 deletion src/StripesContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import hoistNonReactStatics from 'hoist-non-react-statics';

export const StripesContext = React.createContext();
import { StripesContext } from '@folio/stripes-shared-context';

export { StripesContext };

function getDisplayName(WrappedComponent) {
return WrappedComponent.displayName || WrappedComponent.name || 'Component';
Expand Down
4 changes: 2 additions & 2 deletions src/components/About/WarningBanner.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const WarningBanner = ({
<MessageBanner
type="warning"
show={!!missingModulesCount}
dismissable
dismissible
ref={bannerRef}
>
<Headline>{missingModulesMsg}</Headline>
Expand All @@ -61,7 +61,7 @@ const WarningBanner = ({
<MessageBanner
type="warning"
show={!!incompatibleModulesCount}
dismissable
dismissible
ref={bannerRef}
>
<Headline>{incompatibleModuleMsg}</Headline>
Expand Down
4 changes: 2 additions & 2 deletions src/components/LastVisited/LastVisitedContext.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import React from 'react';
import { LastVisitedContext } from '@folio/stripes-shared-context';

export default React.createContext({});
export default LastVisitedContext;
3 changes: 2 additions & 1 deletion src/components/MainNav/CurrentApp/AppCtxMenuContext.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from 'react';
import hoistNonReactStatics from 'hoist-non-react-statics';
import { AppCtxMenuContext } from '@folio/stripes-shared-context';

export const AppCtxMenuContext = React.createContext();
export { AppCtxMenuContext };

export function withAppCtxMenu(Component) {
const WrappedComponent = (props) => {
Expand Down
4 changes: 1 addition & 3 deletions src/components/ModuleHierarchy/ModuleHierarchyContext.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import React from 'react';

const ModuleHierarchyContext = React.createContext();
import { ModuleHierarchyContext } from '@folio/stripes-shared-context';

export default ModuleHierarchyContext;
48 changes: 0 additions & 48 deletions src/components/ModuleTranslator/ModuleTranslator.js

This file was deleted.

1 change: 0 additions & 1 deletion src/components/ModuleTranslator/index.js

This file was deleted.

Loading
Loading