Created
September 10, 2024 12:34
-
-
Save tyler-austin/186e7e28e1f09a06d92769ac06c391da to your computer and use it in GitHub Desktop.
@module-federation/nextjs-mf NextJs config with rewrites
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const path = require('path'); | |
const fs = require('fs'); | |
const NextFederationPlugin = require('@module-federation/nextjs-mf'); | |
const { FederatedTypesPlugin } = require('@module-federation/typescript'); | |
const MODULES = { | |
"host": { | |
"port": 3100 | |
}, | |
"home": { | |
"port": 3001 | |
} | |
}; | |
const findExposures = (root, ignoreDirs) => { | |
// content of root directory | |
const content = fs.readdirSync(root, { withFileTypes: true }); | |
// filter out ignored directories | |
const directories = content.filter(dir => { | |
return dir.isDirectory() && !ignoreDirs.includes(dir.name); | |
}); | |
// walk through directories recursively and find all .ts and .tsx files | |
const fileMap = directories.reduce((acc, directory) => { | |
const dir = path.join(root, directory.name); | |
const walk = curr => { | |
const dirents = fs.readdirSync(curr, { withFileTypes: true }); | |
dirents.forEach(dirent => { | |
const rel = path.relative(root, path.join(curr, dirent.name)); | |
if (dirent.isDirectory()) { | |
walk(path.join(curr, dirent.name)); | |
} else if (dirent.name.endsWith('/index.ts') || dirent.name.endsWith('/index.tsx')) { | |
const key = rel.split('/').slice(0, -1).join('/'); | |
acc[`./${key}`] = `./${rel}`; | |
} else if (dirent.name.endsWith('.ts') || dirent.name.endsWith('.tsx')) { | |
const key = rel.replace(/\.tsx?$/, ''); | |
acc[`./${key}`] = `./${rel}`; | |
} | |
}); | |
}; | |
walk(dir); | |
return acc; | |
}, {}); | |
// return the map of file paths | |
return fileMap; | |
}; | |
const findRemotes = ({ modules, currentModule, isServer }) => { | |
const location = isServer ? 'ssr' : 'chunks'; | |
return Object.entries(modules).reduce((acc, [name, mod]) => { | |
if (name !== currentModule) { | |
const { port } = mod ?? {}; | |
const domain = process.env.NEXT_PUBLIC_LOGIN_REDIRECT_DOMAIN ?? 'http://localhost:3100' | |
acc[name] = `${name}@${domain}/${name}/_next/static/${location}/remoteEntry.js`; | |
} | |
return acc; | |
}, {}); | |
}; | |
const ignoreDirs = ['node_modules', '@mf-types', 'dist', '.next', 'pages', 'lib', 'styles', 'public']; | |
/** @type {import('next').NextConfig} */ | |
module.exports = { | |
reactStrictMode: false, | |
images: { unoptimized: true }, | |
async rewrites() { | |
const mfRewrites = Object.keys(MODULES).filter(key => key !== 'host').map((key) => { | |
return { | |
source: `/${key}/:path*`, | |
destination: `http://localhost:${MODULES[key].port}/:path*`, | |
} | |
}) | |
return mfRewrites | |
}, | |
webpack: (config, context) => { | |
const { isServer } = context; | |
const name = 'host'; | |
const remotes = findRemotes({ | |
modules: MODULES, | |
currentModule: name, | |
isServer, | |
}); | |
const exposes = { | |
...findExposures(__dirname, ignoreDirs), | |
'./pages-map': './pages-map.ts', | |
}; | |
const federationConfig = { | |
filename: 'static/chunks/remoteEntry.js', | |
name, | |
remotes, | |
exposes, | |
// https://module-federation.io/guide/framework/nextjs.html#options | |
extraOptions: { | |
enableImageLoaderFix: true, | |
enableUrlLoaderFix: true, | |
exposePages: true, | |
skipSharingNextInternals: false, | |
automaticPageStitching: false, | |
debug: true, | |
}, | |
shared: { | |
'@tanstack/react-query': { | |
requiredVersion: false, | |
singleton: true, | |
}, | |
'@tanstack/query-core': { | |
requiredVersion: false, | |
singleton: true, | |
}, | |
}, | |
}; | |
config.plugins.push( | |
new NextFederationPlugin(federationConfig), | |
new FederatedTypesPlugin({ | |
federationConfig, | |
typeFetchOptions: { | |
downloadRemoteTypesTimeout: 1000, | |
retryDelay: 1000, | |
}, | |
}), | |
); | |
return config; | |
}, | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment