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

feat: add getModule and getContainer to utilities #476

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/utilities/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,9 @@ export type Loader = Extract<RuleSetRule['use'], { loader?: string }>;
export type EventTypes = 'loadStart' | 'loadComplete' | 'loadError';
type NextRoute = string;
export type PageMap = Record<NextRoute, ModulePath>;

export type GetModuleOptions = {
modulePath: string
exportName?: string
remoteContainer: string | RemoteData
}
59 changes: 57 additions & 2 deletions packages/utilities/src/utils/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import type {
RuntimeRemotesMap,
RuntimeRemote,
WebpackRemoteContainer,
RemoteData,
GetModuleOptions
} from '../types';

type RemoteVars = Record<
Expand Down Expand Up @@ -57,7 +59,7 @@ const getRuntimeRemotes = () => {
}
return acc;
},
{} as RuntimeRemotesMap);
{} as RuntimeRemotesMap);

return runtimeRemotes;
};
Expand Down Expand Up @@ -87,7 +89,7 @@ export const injectScript = (
typeof reference.asyncContainer.then === 'function'
? reference.asyncContainer
: // @ts-ignore
reference.asyncContainer();
reference.asyncContainer();
} else {
// This casting is just to satisfy typescript,
// In reality remoteGlobal will always be a string;
Expand Down Expand Up @@ -205,3 +207,56 @@ export const createRuntimeVariables = (remotes: Remotes) => {
return acc;
}, {} as Record<string, string>);
};

/**
* Returns initialized webpack RemoteContainer.
* If its' script does not loaded - then load & init it firstly.
*/
export const getContainer = async (remoteContainer: string | RemoteData): Promise<WebpackRemoteContainer | undefined> => {

if (!remoteContainer) {
throw Error(`Remote container options is empty`);
}
if (typeof remoteContainer === 'string') {
if (window[remoteContainer]) {
return window[remoteContainer];
}
} else {
if (window['uniqueKey' as keyof typeof remoteContainer]) {
return window['uniqueKey' as keyof typeof remoteContainer];
}
const container = await injectScript({
global: remoteContainer.global,
url: remoteContainer.url,
});

if (container) {
return container;
}
throw Error(`Remote container ${remoteContainer.url} is empty`);
}
}

/**
* Return remote module from container.
* If you provide `exportName` it automatically return exact property value from module.
*
* @example
* remote.getModule('./pages/index', 'default')
*/
export const getModule = async ({ remoteContainer, modulePath, exportName }: GetModuleOptions) => {
const container = await getContainer(remoteContainer);
try {
const modFactory = await container?.get(modulePath);
if (!modFactory) return undefined;
const mod = modFactory();
if (exportName) {
return mod && typeof mod === 'object' ? mod[exportName] : undefined;
} else {
return mod;
}
} catch (error) {
console.log(error)
return undefined
}
}