Skip to content

WIP: reproduce demo #4315

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

Closed
wants to merge 2 commits into from
Closed
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
4 changes: 4 additions & 0 deletions dynamic-remotes-node-typescript/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.idea
node_modules
host/dist
remote/dist
1 change: 1 addition & 0 deletions dynamic-remotes-node-typescript/.nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v20.12.0
9 changes: 9 additions & 0 deletions dynamic-remotes-node-typescript/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Dynamic Remotes on Node w/ TypeScript

Similar to browser side dynamic remotes.

This allows you to dynamically load remote containers on the server.

`pnpm run start` will initiate a build and http server, then the node will load the remotes. The host will poll for changes on the remote and reload when they are detected.

NOTE: HMR is not supported on the server side yet, so we can't get notified of changes in the remote. We have to poll for changes.
6 changes: 6 additions & 0 deletions dynamic-remotes-node-typescript/host/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions dynamic-remotes-node-typescript/host/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
63 changes: 63 additions & 0 deletions dynamic-remotes-node-typescript/host/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { loadRemote, init } from '@module-federation/runtime';
import {performReload, revalidate } from '@module-federation/node/utils';

console.log('hello from host host');

let instance;
let loadedString;
let loadedClass: (new() => any) | null;
let loadedClassInstance;

async function initAndLoad() {
await performReload(true)

// here we assign the return value of the init() function, which can be used to do some more complex
// things with the module federation runtime
instance = init({
name: 'host',
remotes: [
{
name: 'remote',
entry: 'http://localhost:3002/remoteEntry.js',
},
],
});

// NOTE - below we use .default as the "export default" style in the remote. This changes
// based on the remote's export style.
//
// Other examples:
// - using module.exports would not require the .default
// - using named exports would require the specific export name on the remotely loaded object
// (e.g. export class TestClass {} would require loadedObject.TestClass)

loadedString = (await loadRemote('remote/string') as any).default;
console.log('loaded string', loadedString);

loadedClass = (await loadRemote('remote/class') as any).default;
loadedClassInstance = loadedClass ? new loadedClass() : null;

console.log('current loaded class', loadedClass);
console.log('current loaded class test value', loadedClassInstance?.getTestValue());
console.log('current loaded class run test', await loadedClassInstance?.runTest());
}

initAndLoad();

setInterval(async () => {
console.log('host(): checking remote for updates');

// NOTE: this is called the first time an update is detected on the remote and never again
// NOTE: had to patch hot-reload.js to get this to not throw an error
// we automatically reset require cache, so the reload callback is only if you need to do something else
const shouldReload = await revalidate();

// do something extra after revalidation
if (shouldReload) {
// reload the server
console.log('host(): should reload');
initAndLoad();
} else {
console.log('host(): should not reload');
}
}, 5000);
8 changes: 8 additions & 0 deletions dynamic-remotes-node-typescript/host/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"compilerOptions": {
"rootDir": "src",
"outDir": "dist"
},
"include": ["src/**/**.ts"],
"exclude": ["node_modules", "!node_modules/@types"]
}
45 changes: 45 additions & 0 deletions dynamic-remotes-node-typescript/host/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const { UniversalFederationPlugin } = require('@module-federation/node');
const webpack = require('webpack');

module.exports = {
entry: './src/index.ts',
mode: 'development',
target: 'async-node',
externals: [],
output: {
publicPath: 'http://localhost:3001/',
library: { type: 'commonjs-module' },
},
resolve: {
extensions: ['.ts', '.tsx', '.js'],
},
module: {
noParse: /yargs/,
rules: [
{
test: /\.tsx?$/,
use: [
{
loader: 'ts-loader',
options: {
transpileOnly: false, // Enables type-checking and .d.ts file emission
},
},
],
exclude: /node_modules/,
},
],
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new UniversalFederationPlugin({
remoteType: 'script',
isServer: true,
name: 'host',
useRuntimePlugin: true,
exposes: {
'./noop': './src/noop.ts',
},
}),
],
};
Loading
Loading