Skip to content

Commit

Permalink
Add ShellHooksProvider and related hooks for managing shell hooks and…
Browse files Browse the repository at this point in the history
… alerts
  • Loading branch information
hervedombya committed Dec 16, 2024
1 parent c571388 commit b78866f
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 17 deletions.
32 changes: 32 additions & 0 deletions build/ModuleFederation.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,36 @@ export declare const ComponentWithFederatedImports: <Props extends {}>({ renderO
module: string;
}[];
}) => React.JSX.Element;
type ShellHooks<T extends {
shellHooks: any;
}> = T["shellHooks"];
type ShellAlerts<T extends {
shellAlerts: any;
}> = T["shellAlerts"];
type Listener = () => void;
export declare const shellHooksStore: {
getShellHooks: () => any;
subscribe: (listener: Listener) => () => void;
setShellHooks: (newHooks: any) => void;
};
export declare const shellAlertsStore: {
getShellAlerts: () => any;
subscribe: (listener: Listener) => () => void;
setShellAlerts: (newAlerts: any) => void;
};
export declare const useShellHooks: <T extends {
shellHooks: any;
}>() => ShellHooks<T>;
export declare const useShellAlerts: <T extends {
shellAlerts: any;
}>() => ShellAlerts<T>;
export declare const ShellHooksProvider: <T extends {
shellHooks: any;
}, K extends {
shellAlerts: any;
}>({ shellHooks, shellAlerts, children, }: {
shellHooks: ShellHooks<T>;
shellAlerts: ShellAlerts<K>;
children: ReactNode;
}) => React.JSX.Element;
export {};
71 changes: 68 additions & 3 deletions build/ModuleFederation.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ComponentWithFederatedImports = exports.lazyWithModules = exports.FederatedComponent = exports.useCurrentApp = exports.loadModule = exports.registerAndLoadModule = void 0;
exports.ShellHooksProvider = exports.useShellAlerts = exports.useShellHooks = exports.shellAlertsStore = exports.shellHooksStore = exports.ComponentWithFederatedImports = exports.lazyWithModules = exports.FederatedComponent = exports.useCurrentApp = exports.loadModule = exports.registerAndLoadModule = void 0;
const runtime_1 = require("@module-federation/enhanced/runtime");
const react_1 = __importStar(require("react"));
const registeredApps = [];
Expand Down Expand Up @@ -66,8 +66,9 @@ function FederatedComponent({ url, scope, module, app, renderOnLoading, props, }
throw new Error("Can't federate a component without url, scope and module");
}
return (react_1.default.createElement(react_1.Suspense, { fallback: renderOnLoading !== null && renderOnLoading !== void 0 ? renderOnLoading : react_1.default.createElement(react_1.default.Fragment, null, "Loading...") },
react_1.default.createElement(CurrentAppContext.Provider, { value: app },
react_1.default.createElement(Component, { ...props }))));
react_1.default.createElement(exports.ShellHooksProvider, { shellHooks: props.shellHooks, shellAlerts: props.shellAlerts },
react_1.default.createElement(CurrentAppContext.Provider, { value: app },
react_1.default.createElement(Component, { ...props })))));
}
exports.FederatedComponent = FederatedComponent;
const lazyWithModules = (functionComponent, ...modules) => {
Expand Down Expand Up @@ -96,3 +97,67 @@ const ComponentWithFederatedImports = ({ renderOnError, renderOnLoading, compone
react_1.default.createElement(Component, { ...componentProps })));
};
exports.ComponentWithFederatedImports = ComponentWithFederatedImports;
const createShellHooksStore = () => {
let shellHooks = null;
const listeners = new Set();
return {
getShellHooks: () => shellHooks,
subscribe: (listener) => {
listeners.add(listener);
return () => {
listeners.delete(listener);
};
},
setShellHooks: (newHooks) => {
if (shellHooks !== newHooks) {
shellHooks = newHooks;
listeners.forEach((listener) => listener());
}
},
};
};
const createShellAlertsStore = () => {
let shellAlerts = null;
const listeners = new Set();
return {
getShellAlerts: () => shellAlerts,
subscribe: (listener) => {
listeners.add(listener);
return () => {
listeners.delete(listener);
};
},
setShellAlerts: (newAlerts) => {
if (shellAlerts !== newAlerts) {
shellAlerts = newAlerts;
listeners.forEach((listener) => listener());
}
},
};
};
exports.shellHooksStore = createShellHooksStore();
exports.shellAlertsStore = createShellAlertsStore();
const useShellHooks = () => {
const hooks = (0, react_1.useSyncExternalStore)(exports.shellHooksStore.subscribe, exports.shellHooksStore.getShellHooks);
if (!hooks) {
throw new Error("useShellHooks must be used within a ShellHooksProvider and initialized with valid hooks.");
}
return hooks;
};
exports.useShellHooks = useShellHooks;
const useShellAlerts = () => {
const alerts = (0, react_1.useSyncExternalStore)(exports.shellAlertsStore.subscribe, exports.shellAlertsStore.getShellAlerts);
if (!alerts) {
throw new Error("useShellAlerts must be used within a ShellHooksProvider and initialized with valid alerts.");
}
return alerts;
};
exports.useShellAlerts = useShellAlerts;
const ShellHooksProvider = ({ shellHooks, shellAlerts, children, }) => {
(0, react_1.useMemo)(() => {
exports.shellHooksStore.setShellHooks(shellHooks);
exports.shellAlertsStore.setShellAlerts(shellAlerts);
}, [shellHooks, shellAlerts]);
return react_1.default.createElement(react_1.default.Fragment, null, children);
};
exports.ShellHooksProvider = ShellHooksProvider;
39 changes: 25 additions & 14 deletions src/ModuleFederation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,13 @@ export const ComponentWithFederatedImports = <Props extends {}>({
);
};

type ShellHooks = ReturnType<any>;
type ShellAlerts = ReturnType<any>;
type ShellHooks<T extends { shellHooks: any }> = T["shellHooks"];
type ShellAlerts<T extends { shellAlerts: any }> = T["shellAlerts"];

type Listener = () => void;

const createShellHooksStore = () => {
let shellHooks: ShellHooks | null = null;
const createShellHooksStore = <T extends { shellHooks: any }>() => {
let shellHooks: ShellHooks<T> | null = null;

const listeners: Set<Listener> = new Set();

Expand All @@ -196,7 +196,7 @@ const createShellHooksStore = () => {
};
},

setShellHooks: (newHooks: ShellHooks) => {
setShellHooks: (newHooks: ShellHooks<T>) => {
if (shellHooks !== newHooks) {
shellHooks = newHooks;
listeners.forEach((listener) => listener());
Expand All @@ -205,8 +205,8 @@ const createShellHooksStore = () => {
};
};

const createShellAlertsStore = () => {
let shellAlerts: ShellAlerts | null = null;
const createShellAlertsStore = <T extends { shellAlerts: any }>() => {
let shellAlerts: ShellAlerts<T> | null = null;
const listeners: Set<Listener> = new Set();

return {
Expand All @@ -219,7 +219,7 @@ const createShellAlertsStore = () => {
};
},

setShellAlerts: (newAlerts: ShellAlerts) => {
setShellAlerts: (newAlerts: ShellAlerts<T>) => {
if (shellAlerts !== newAlerts) {
shellAlerts = newAlerts;
listeners.forEach((listener) => listener());
Expand All @@ -231,7 +231,9 @@ const createShellAlertsStore = () => {
export const shellHooksStore = createShellHooksStore();
export const shellAlertsStore = createShellAlertsStore();

export const useShellHooks = (): ShellHooks => {
export const useShellHooks = <
T extends { shellHooks: any }
>(): ShellHooks<T> => {
const hooks = useSyncExternalStore(
shellHooksStore.subscribe,
shellHooksStore.getShellHooks
Expand All @@ -246,7 +248,9 @@ export const useShellHooks = (): ShellHooks => {
return hooks;
};

export const useShellAlerts = (): ShellAlerts => {
export const useShellAlerts = <
T extends { shellAlerts: any }
>(): ShellAlerts<T> => {
const alerts = useSyncExternalStore(
shellAlertsStore.subscribe,
shellAlertsStore.getShellAlerts
Expand All @@ -261,11 +265,18 @@ export const useShellAlerts = (): ShellAlerts => {
return alerts;
};

export const ShellHooksProvider: FC<{
shellHooks: ShellHooks;
shellAlerts: ShellAlerts;
export const ShellHooksProvider = <
T extends { shellHooks: any },
K extends { shellAlerts: any }
>({
shellHooks,
shellAlerts,
children,
}: {
shellHooks: ShellHooks<T>;
shellAlerts: ShellAlerts<K>;
children: ReactNode;
}> = ({ shellHooks, shellAlerts, children }) => {
}) => {
useMemo(() => {
shellHooksStore.setShellHooks(shellHooks);
shellAlertsStore.setShellAlerts(shellAlerts);
Expand Down

0 comments on commit b78866f

Please sign in to comment.