// ./shared.js
const React = require('react');
const createMatcher = require('feather-route-matcher');
const { injectScript } = require('@module-federation/nextjs-mf/utils');
import dynamic from 'next/dynamic';
const remoteVars = process.env.REMOTES || {};
export const remotes = Object.entries(remoteVars).reduce((acc, item) => {
const [key, value] = item;
if (typeof value !== 'string') {
acc[key] = {
global: value
};
return acc;
}
const [global, url] = value.split('@');
acc[key] = {
url,
global
};
return acc;
}, {});
async function matchFederatedPage(path) {
// console.log(remotes, 'shared');
console.log(remoteVars, 'remoteVars');
const maps = await Promise.all(
Object.keys(remotes).map(async remote => {
const foundContainer = injectScript(remote);
const container = await foundContainer;
return container
.get('./pages-map')
.then(factory => ({ remote, config: factory().default }))
.catch(() => null);
})
);
const config = {};
for (const map of maps) {
if (!map) continue;
for (let [path, mod] of Object.entries(map.config)) {
config[path] = {
remote: map.remote,
module: mod
};
}
}
console.log(config);
const matcher = createMatcher.default(config);
return matcher(path);
}
module.exports = {
matchFederatedPage,
createFederatedCatchAll() {
const FederatedCatchAll = initialProps => {
const [lazyProps, setProps] = React.useState({});
const {
FederatedPage,
render404,
renderError,
needsReload,
role,
...props
} = {
...lazyProps,
...initialProps
};
console.log(props);
React.useEffect(() => {
if (needsReload) {
const runUnderlayingGIP = async () => {
const federatedProps = await FederatedCatchAll.getInitialProps(
props
);
setProps(federatedProps);
};
runUnderlayingGIP();
}
}, []);
if (render404) {
// TODO: Render 404 page
return React.createElement('h1', {}, '404 Not Found');
}
if (renderError) {
// TODO: Render error page
return React.createElement('h1', {}, 'Oops, something went wrong.');
}
if (FederatedPage) {
return React.createElement(FederatedPage, props);
}
return null;
};
FederatedCatchAll.getInitialProps = async ctx => {
// Bot marks "req, res, AppTree" as unused but those are vital to not get circular-dependency error
const { err, req, res, AppTree, ...props } = ctx;
if (err) {
// TODO: Run getInitialProps for error page
return { renderError: true, ...props };
}
// Custom
let role;
//
if (!process.browser) {
role = getCookie('token', req?.headers?.cookie);
return { needsReload: true, ...props, role, remotes };
} else {
role = cookieCutter.get('token');
}
console.log('in browser', ctx.asPath);
const matchedPage = await matchFederatedPage(ctx.asPath);
try {
console.log('matchedPage', matchedPage);
const remote = matchedPage?.value?.remote;
const mod = matchedPage?.value?.module;
if (!remote || !mod) {
// TODO: Run getInitialProps for 404 page
return { render404: true, ...props };
}
console.log('loading exposed module', mod, 'from remote', remote);
const container = await injectScript(remote);
const FederatedPage = await container
.get(mod)
.then(factory => factory().default);
console.log('FederatedPage', FederatedPage);
if (!FederatedPage) {
// TODO: Run getInitialProps for 404 page
return { render404: true, ...props };
}
const modifiedContext = {
...ctx,
query: matchedPage.params
};
const federatedPageProps =
(await FederatedPage.getInitialProps?.(modifiedContext)) || {};
return { ...federatedPageProps, FederatedPage, role, matchedPage };
} catch (err) {
console.log('err', err);
// TODO: Run getInitialProps for error page
return { renderError: true, ...props };
}
};
return FederatedCatchAll;
}
};
// pages/[...slug].js
import { createFederatedCatchAll } from '../shared.js';
export default createFederatedCatchAll();
Hi,
I have NextJs v13 remote and host applications. Remote exposes all its pages and it takes over when mounted in host. So all the routing is taken care from remote application.
My problem is how can I get the getServerSideProps
of all the pages in remotes when each is mounted in host to be executed and pass the props to mounted remote component?
Above is the host's catchall slug route and shared.js file that does the work of finding the right module to load based on the route. Its just that getServerSideProps
dont get executed and its a bottleneck in my POC.
I tried to run matchFederatedPage('/path')
from nextjs page/getServersideProps function but it throws errors saying unhandledRejection: TypeError: Cannot read property 'asyncContainer' of undefined
Is there any way to load up the right module + have the getServerSideProps
function executed of remotes in slug route of host?
Here are my repo links
Host - https://github.com/gitneeraj/nextjs-mf-host
Remote1 - https://github.com/gitneeraj/nextjs-mf-remote1
PS - I have already posted this on examples repo so sorry for the duplication. I really need this to get working in my project.
~ Thanks & Peace