I have a folder structure as below. To summarize, it is to implement Module Federation (Host and Child module) and in this case, I am using a shared module (inside shared-context which is just for React Context API object)
mymfe
shared-context
src
index.js
mySharedDataContext.js
package.json
my-host-ui
my-web
craco.config.js
modulefederation.config.js
package.json
src
App.js
My "shared-context" module only has a Context API object which is re-exported and I want to consume the same in my-host-ui
So in the "shared-context"'s index.js, I am re-exporting the Context API object which I want to consume in App.js as below
export {default as MySharedDataContextProvider} from "./mySharedDataContext"
And mySharedDataContext.js is a standard Context API hook as below;
import React, {useState} from 'react';
export const MySharedDataContext = React.createContext();
export default ({children}) => {
const [mySharedData, setMySharedData] = useState({});
return (
<MySharedDataContext.Provider value={[mySharedData, setMySharedData]}>
{children}
</MySharedDataContext.Provider>
);
}
Now coming to HOST module configurations. I have the following configs;
craco.config.js
const path = require('path');
module.exports = {
mode: 'development',
devServer: {
static: 'src',
hot: true,
port: 3000
},
resolve: {
alias: {
'shared-context': path.resolve(__dirname, '../../shared-context'),
},
},
plugins:[
{
plugin: require('./config/craco-federation')
},
]
};
craco-federation.js is as below
const webpack = require("webpack");
const paths = require("react-scripts/config/paths");
const ExternalTemplateRemotesPlugin = require("external-remotes-plugin");
const getModuleFederationConfigPath = (additionalPaths = []) => {
const path = require("path");
const fs = require("fs");
const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath);
const moduleFederationConfigFiles = [
"modulefederation.config.js",
...additionalPaths,
];
return moduleFederationConfigFiles
.map(resolveApp)
.filter(fs.existsSync)
.shift();
};
module.exports = {
overrideWebpackConfig: ({ webpackConfig, pluginOptions }) => {
const moduleFederationConfigPath = getModuleFederationConfigPath();
if (moduleFederationConfigPath) {
webpackConfig.output.publicPath = "auto";
if (pluginOptions?.useNamedChunkIds) {
webpackConfig.optimization.chunkIds = "named";
}
const htmlWebpackPlugin = webpackConfig.plugins.find(
(plugin) => plugin.constructor.name === "HtmlWebpackPlugin"
);
htmlWebpackPlugin.userOptions = {
...htmlWebpackPlugin.userOptions,
publicPath: paths.publicUrlOrPath,
excludeChunks: [require(moduleFederationConfigPath).name],
};
webpackConfig.plugins = [
...webpackConfig.plugins,
new webpack.container.ModuleFederationPlugin(
require(moduleFederationConfigPath)
),
new ExternalTemplateRemotesPlugin(),
];
}
return webpackConfig;
}
};
modulefederation.config.js
const { dependencies } = require('./package.json');
module.exports = {
name: "host",
remotes: {
childMfe: "childMfe@http://localhost:3001/remoteEntry.js"
},
filename: "remoteEntry.js",
shared: {
...dependencies,
react: {
singleton: true,
requiredVersion: dependencies['react'],
},
'react-dom': {
singleton: true,
requiredVersion: dependencies['react-dom'],
},
'shared-context': {
import: 'shared-context',
requiredVersion: require('../../shared-context/package.json').version,
}
}
};
And in the App.js, I am trying to import as below
import MySharedDataContextProvider from 'shared-context';
function App() {
return (
<MySharedDataContextProvider>
</MySharedDataContextProvider>
}
When I am trying to build, I am getting the below error.
ERROR in resolving fallback for shared module shared-context
Module not found: Error: Can't resolve 'shared-context' in 'C:\mfe\my-host-ui\my-web\src'
Not sure what is the correct way to import the shared context.