Skip to content

Commit

Permalink
Feature/support esm import remote (#1469)
Browse files Browse the repository at this point in the history
* Support ESM with ImportRemote

* Switch to eval, revert module TSC type

* Convert to TS module Node16

* Update ReadMe
  • Loading branch information
RussellCanfield authored Sep 30, 2023
1 parent 69c20c0 commit 56c938c
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 13 deletions.
15 changes: 15 additions & 0 deletions packages/utilities/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ Usage looks something like this:
```js
import { importRemote } from '@module-federation/utilities';

// --
// If it's a regular js module:
// --
importRemote({
url: 'http://localhost:3001',
scope: 'Foo',
Expand All @@ -65,7 +67,20 @@ importRemote({
},
);

// --
// If it's a ESM module (this is currently the default for NX):
// --
const Bar = lazy(() => importRemote({ url: 'http://localhost:3001', scope: 'Foo', module: 'Bar', esm: true }));

return (
<Suspense fallback={<div>Loading Bar...</div>}>
<Bar />
</Suspense>
);

// --
// If Bar is a React component you can use it with lazy and Suspense just like a dynamic import:
// --
const Bar = lazy(() => importRemote({ url: 'http://localhost:3001', scope: 'Foo', module: 'Bar' }));

return (
Expand Down
2 changes: 1 addition & 1 deletion packages/utilities/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"tsConfig": "packages/utilities/tsconfig.lib.json",
"assets": ["packages/utilities/*.md"],
"buildableProjectDepsInPackageJsonType": "dependencies",
"updateBuildableProjectDepsInPackageJson": true,
"updateBuildableProjectDepsInPackageJson": true
}
},
"publish": {
Expand Down
38 changes: 29 additions & 9 deletions packages/utilities/src/utils/importRemote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export interface ImportRemoteOptions {
module: string;
remoteEntryFileName?: string;
bustRemoteEntryCache?: boolean;
esm?: boolean;
}

/**
Expand All @@ -43,7 +44,7 @@ const REMOTE_ENTRY_FILE = 'remoteEntry.js';
* @returns {Promise<void>} A promise that resolves when the remote is loaded
*/
const loadRemote = (
url: ImportRemoteOptions['url'],
url: RemoteData['url'],
scope: ImportRemoteOptions['scope'],
bustRemoteEntryCache: ImportRemoteOptions['bustRemoteEntryCache'],
) =>
Expand All @@ -67,6 +68,25 @@ const loadRemote = (
);
});

const loadEsmRemote = async (
url: RemoteData['url'],
scope: ImportRemoteOptions['scope'],
) => {
const module = await import(/* webpackIgnore: true */ url);

if (!module) {
throw new Error(
`Unable to load requested remote from ${url} with scope ${scope}`,
);
}

window[scope] = {
...module,
__initializing: false,
__initialized: false,
} satisfies WebpackRemoteContainer;
};

/**
* Function to initialize sharing
* @async
Expand Down Expand Up @@ -114,6 +134,7 @@ export const importRemote = async <T>({
module,
remoteEntryFileName = REMOTE_ENTRY_FILE,
bustRemoteEntryCache = true,
esm = false,
}: ImportRemoteOptions): Promise<T> => {
const remoteScope = scope as unknown as number;
if (!window[remoteScope]) {
Expand All @@ -125,15 +146,14 @@ export const importRemote = async <T>({
remoteUrl = await url();
}

const remoteUrlWithEntryFile = `${remoteUrl}/${remoteEntryFileName}`;

const asyncContainer = !esm
? loadRemote(remoteUrlWithEntryFile, scope, bustRemoteEntryCache)
: loadEsmRemote(remoteUrlWithEntryFile, scope);

// Load the remote and initialize the share scope if it's empty
await Promise.all([
loadRemote(
`${remoteUrl}/${remoteEntryFileName}`,
scope,
bustRemoteEntryCache,
),
initSharing(),
]);
await Promise.all([asyncContainer, initSharing()]);
if (!window[remoteScope]) {
throw new Error(
`Remote loaded successfully but ${scope} could not be found! Verify that the name is correct in the Webpack configuration!`,
Expand Down
6 changes: 4 additions & 2 deletions packages/utilities/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"target": "ES2015",
"module": "commonjs",
"module": "Node16",
"moduleResolution": "Node16",
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
"noFallthroughCasesInSwitch": true,
"resolveJsonModule": true
},
"files": [],
"include": [],
Expand Down
2 changes: 1 addition & 1 deletion packages/utilities/tsconfig.lib.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"jsx": "react",
"outDir": "../../dist/out-tsc",
"declaration": true,
"types": ["node"]
"types": ["node"],
},
"include": ["**/*.ts", "**/*.tsx"],
"exclude": ["jest.config.ts", "**/*.spec.ts", "**/*.test.ts", "**/*.test.js"]
Expand Down

0 comments on commit 56c938c

Please sign in to comment.