I am currently exploring about micro frontend with Module Federation. I just forked a sandbox, tried it with success when the both modules available. It has 2 modules, app1
as the host, and app2
as the remote component. But as I think that each modules in module federation should be independent, I tried to make the app2
unavailable as I didn’t start it. Therefore I got error when I run the app1
, it finished loading with displaying the fallback of the React’s Suspense
, but milliseconds later, it becomes blank as there’s error I can’t retrieve thus I don’t really know.
After that, I tried Webpack’s Promise Based Dynamic Remotes, then my webpack-config.js
becomes like this:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { ModuleFederationPlugin } = require('webpack').container;
const ExternalTemplateRemotesPlugin = require('external-remotes-plugin');
const path = require('path');
module.exports = {
entry: './src/index',
mode: 'development',
devServer: {
static: path.join(__dirname, 'dist'),
port: 3001,
},
output: {
publicPath: 'auto',
},
module: {
rules: [
{
test: /.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
options: {
presets: ['@babel/preset-react'],
},
},
],
},
plugins: [
new ModuleFederationPlugin({
name: 'app1',
remotes: {
app2: Promise((resolve) => {
const urlParams = new URLSearchParams(window.location.search);
const version = urlParams.get('app1VersionParam');
// This part depends on how you plan on hosting and versioning your federated modules
const remoteUrlWithVersion = '[app2Url]' + '/remoteEntry.js';
const script = document.createElement('script');
script.src = remoteUrlWithVersion;
script.onload = () => {
// the injected script has loaded and is available on window
// we can now resolve this Promise
const proxy = {
get: (request) => window.app1.get(request),
init: (arg) => {
try {
return window.app1.init(arg);
} catch (e) {
console.log('remote container already initialized');
}
},
};
resolve(proxy);
};
// inject this script with the src set to the versioned remoteEntry.js
document.head.appendChild(script);
}),
// "app2@[app2Url]/remoteEntry.js",
},
shared: { react: { singleton: true }, 'react-dom': { singleton: true } },
}),
new ExternalTemplateRemotesPlugin(),
new HtmlWebpackPlugin({
template: './public/index.html',
}),
],
};
I tried start the app1
again, then this error comes:
$ webpack serve
[webpack-cli] Failed to load '/home/projects/github-rl5uyr/app1/webpack.config.js' config
[webpack-cli] TypeError: undefined is not a promise
at Promise (<anonymous>)
at Object.eval (/home/projects/github-rl5uyr/app1/webpack.config.js:32:15)
at Object.function (https://github-rl5uyr.w.staticblitz.com/blitz.01faa899fac41642342f4b7113feacabea334fa1.js:11:114831)
at Module._compile (https://github-rl5uyr.w.staticblitz.com/blitz.01faa899fac41642342f4b7113feacabea334fa1.js:6:167880)
at Object.Module._extensions..js (https://github-rl5uyr.w.staticblitz.com/blitz.01faa899fac41642342f4b7113feacabea334fa1.js:6:168239)
at Module.load (https://github-rl5uyr.w.staticblitz.com/blitz.01faa899fac41642342f4b7113feacabea334fa1.js:6:166317)
at Function.Module._load (https://github-rl5uyr.w.staticblitz.com/blitz.01faa899fac41642342f4b7113feacabea334fa1.js:6:163857)
at Module.require (https://github-rl5uyr.w.staticblitz.com/blitz.01faa899fac41642342f4b7113feacabea334fa1.js:6:166635)
at i (https://github-rl5uyr.w.staticblitz.com/blitz.01faa899fac41642342f4b7113feacabea334fa1.js:6:427483)
at _0x5301a6 (https://github-rl5uyr.w.staticblitz.com/blitz.01faa899fac41642342f4b7113feacabea334fa1.js:11:114450)
So, can the module federations run independently each other? If not, what’s the real difference as normal library dependencies of monolith front end instead of this sophisticated micro frontend, that I assumed it should be able to work independently like microservices?