feat(react): add withModuleFederationForSSR function (#13276)
This commit is contained in:
parent
b902849bc4
commit
8be2980339
@ -1,8 +1,12 @@
|
|||||||
import { withModuleFederation } from './src/module-federation/with-module-federation';
|
import { withModuleFederation } from './src/module-federation/with-module-federation';
|
||||||
|
import { withModuleFederationForSSR } from './src/module-federation/with-module-federation-ssr';
|
||||||
|
|
||||||
export { withModuleFederation };
|
export { withModuleFederation };
|
||||||
|
export { withModuleFederationForSSR };
|
||||||
|
|
||||||
// Support for older generated code: `const withModuleFederation = require('@nrwl/react/module-federation')`
|
// Support for older generated code: `const withModuleFederation = require('@nrwl/react/module-federation')`
|
||||||
module.exports = withModuleFederation;
|
module.exports = withModuleFederation;
|
||||||
|
|
||||||
// Allow newer generated code to work: `const { withModuleFederation } = require(...)`;
|
// Allow newer generated code to work: `const { withModuleFederation } = require(...)`;
|
||||||
module.exports.withModuleFederation = withModuleFederation;
|
module.exports.withModuleFederation = withModuleFederation;
|
||||||
|
module.exports.withModuleFederationForSSR = withModuleFederationForSSR;
|
||||||
|
|||||||
65
packages/react/src/module-federation/utils.ts
Normal file
65
packages/react/src/module-federation/utils.ts
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import {
|
||||||
|
applyAdditionalShared,
|
||||||
|
applySharedFunction,
|
||||||
|
createProjectGraphAsync,
|
||||||
|
getDependentPackagesForProject,
|
||||||
|
mapRemotes,
|
||||||
|
mapRemotesForSSR,
|
||||||
|
ModuleFederationConfig,
|
||||||
|
ProjectConfiguration,
|
||||||
|
ProjectGraph,
|
||||||
|
readCachedProjectGraph,
|
||||||
|
sharePackages,
|
||||||
|
shareWorkspaceLibraries,
|
||||||
|
} from '@nrwl/devkit';
|
||||||
|
|
||||||
|
export async function getModuleFederationConfig(
|
||||||
|
mfConfig: ModuleFederationConfig,
|
||||||
|
determineRemoteUrl: (remote: string) => string,
|
||||||
|
options: { isServer: boolean } = { isServer: false }
|
||||||
|
) {
|
||||||
|
let projectGraph: ProjectGraph<ProjectConfiguration>;
|
||||||
|
try {
|
||||||
|
projectGraph = readCachedProjectGraph();
|
||||||
|
} catch (e) {
|
||||||
|
projectGraph = await createProjectGraphAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
const project = projectGraph.nodes[mfConfig.name]?.data;
|
||||||
|
|
||||||
|
if (!project) {
|
||||||
|
throw Error(
|
||||||
|
`Cannot find project "${mfConfig.name}". Check that the name is correct in module-federation.config.js`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const dependencies = getDependentPackagesForProject(
|
||||||
|
projectGraph,
|
||||||
|
mfConfig.name
|
||||||
|
);
|
||||||
|
const sharedLibraries = shareWorkspaceLibraries(
|
||||||
|
dependencies.workspaceLibraries
|
||||||
|
);
|
||||||
|
|
||||||
|
const npmPackages = sharePackages(dependencies.npmPackages);
|
||||||
|
|
||||||
|
const sharedDependencies = {
|
||||||
|
...sharedLibraries.getLibraries(),
|
||||||
|
...npmPackages,
|
||||||
|
};
|
||||||
|
|
||||||
|
applySharedFunction(sharedDependencies, mfConfig.shared);
|
||||||
|
applyAdditionalShared(
|
||||||
|
sharedDependencies,
|
||||||
|
mfConfig.additionalShared,
|
||||||
|
projectGraph
|
||||||
|
);
|
||||||
|
|
||||||
|
const mapRemotesFunction = options.isServer ? mapRemotesForSSR : mapRemotes;
|
||||||
|
const mappedRemotes =
|
||||||
|
!mfConfig.remotes || mfConfig.remotes.length === 0
|
||||||
|
? {}
|
||||||
|
: mapRemotesFunction(mfConfig.remotes, 'js', determineRemoteUrl);
|
||||||
|
|
||||||
|
return { sharedLibraries, sharedDependencies, mappedRemotes };
|
||||||
|
}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
import { ModuleFederationConfig } from '@nrwl/devkit';
|
||||||
|
import { readCachedProjectConfiguration } from 'nx/src/project-graph/project-graph';
|
||||||
|
import { getModuleFederationConfig } from './utils';
|
||||||
|
|
||||||
|
function determineRemoteUrl(remote: string) {
|
||||||
|
const remoteConfiguration = readCachedProjectConfiguration(remote);
|
||||||
|
const serveTarget = remoteConfiguration?.targets?.serve;
|
||||||
|
|
||||||
|
if (!serveTarget) {
|
||||||
|
throw new Error(
|
||||||
|
`Cannot automatically determine URL of remote (${remote}). Looked for property "host" in the project's "serve" target.\n
|
||||||
|
You can also use the tuple syntax in your webpack config to configure your remotes. e.g. \`remotes: [['remote1', '//localhost:4201']]\``
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const host = serveTarget.options?.host ?? '//localhost';
|
||||||
|
const port = serveTarget.options?.port ?? 4201;
|
||||||
|
return `${
|
||||||
|
host.endsWith('/') ? host.slice(0, -1) : host
|
||||||
|
}:${port}/server/remoteEntry.js`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function withModuleFederationForSSR(
|
||||||
|
options: ModuleFederationConfig
|
||||||
|
) {
|
||||||
|
const reactWebpackConfig = require('../../plugins/webpack');
|
||||||
|
|
||||||
|
const { sharedLibraries, sharedDependencies, mappedRemotes } =
|
||||||
|
await getModuleFederationConfig(options, determineRemoteUrl, {
|
||||||
|
isServer: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (config) => {
|
||||||
|
config = reactWebpackConfig(config);
|
||||||
|
|
||||||
|
config.target = false;
|
||||||
|
config.output.uniqueName = options.name;
|
||||||
|
config.optimization = {
|
||||||
|
runtimeChunk: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
config.plugins.push(
|
||||||
|
new (require('@module-federation/node').UniversalFederationPlugin)(
|
||||||
|
{
|
||||||
|
name: options.name,
|
||||||
|
filename: 'remoteEntry.js',
|
||||||
|
exposes: options.exposes,
|
||||||
|
remotes: mappedRemotes,
|
||||||
|
shared: {
|
||||||
|
...sharedDependencies,
|
||||||
|
},
|
||||||
|
library: {
|
||||||
|
type: 'commonjs-module',
|
||||||
|
},
|
||||||
|
isServer: true,
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
),
|
||||||
|
sharedLibraries.getReplacementPlugin()
|
||||||
|
);
|
||||||
|
|
||||||
|
return config;
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -1,17 +1,6 @@
|
|||||||
import {
|
import { ModuleFederationConfig } from '@nrwl/devkit';
|
||||||
applyAdditionalShared,
|
|
||||||
applySharedFunction,
|
|
||||||
createProjectGraphAsync,
|
|
||||||
getDependentPackagesForProject,
|
|
||||||
mapRemotes,
|
|
||||||
ModuleFederationConfig,
|
|
||||||
ProjectConfiguration,
|
|
||||||
ProjectGraph,
|
|
||||||
readCachedProjectGraph,
|
|
||||||
sharePackages,
|
|
||||||
shareWorkspaceLibraries,
|
|
||||||
} from '@nrwl/devkit';
|
|
||||||
import { readCachedProjectConfiguration } from 'nx/src/project-graph/project-graph';
|
import { readCachedProjectConfiguration } from 'nx/src/project-graph/project-graph';
|
||||||
|
import { getModuleFederationConfig } from './utils';
|
||||||
import ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
|
import ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
|
||||||
|
|
||||||
function determineRemoteUrl(remote: string) {
|
function determineRemoteUrl(remote: string) {
|
||||||
@ -34,42 +23,9 @@ function determineRemoteUrl(remote: string) {
|
|||||||
|
|
||||||
export async function withModuleFederation(options: ModuleFederationConfig) {
|
export async function withModuleFederation(options: ModuleFederationConfig) {
|
||||||
const reactWebpackConfig = require('../../plugins/webpack');
|
const reactWebpackConfig = require('../../plugins/webpack');
|
||||||
let projectGraph: ProjectGraph<ProjectConfiguration>;
|
|
||||||
try {
|
|
||||||
projectGraph = readCachedProjectGraph();
|
|
||||||
} catch (e) {
|
|
||||||
projectGraph = await createProjectGraphAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
const project = projectGraph.nodes[options.name]?.data;
|
const { sharedDependencies, sharedLibraries, mappedRemotes } =
|
||||||
|
await getModuleFederationConfig(options, determineRemoteUrl);
|
||||||
if (!project) {
|
|
||||||
throw Error(
|
|
||||||
`Cannot find project "${options.name}". Check that the name is correct in module-federation.config.js`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const dependencies = getDependentPackagesForProject(
|
|
||||||
projectGraph,
|
|
||||||
options.name
|
|
||||||
);
|
|
||||||
const sharedLibraries = shareWorkspaceLibraries(
|
|
||||||
dependencies.workspaceLibraries
|
|
||||||
);
|
|
||||||
|
|
||||||
const npmPackages = sharePackages(dependencies.npmPackages);
|
|
||||||
|
|
||||||
const sharedDependencies = {
|
|
||||||
...sharedLibraries.getLibraries(),
|
|
||||||
...npmPackages,
|
|
||||||
};
|
|
||||||
|
|
||||||
applySharedFunction(sharedDependencies, options.shared);
|
|
||||||
applyAdditionalShared(
|
|
||||||
sharedDependencies,
|
|
||||||
options.additionalShared,
|
|
||||||
projectGraph
|
|
||||||
);
|
|
||||||
|
|
||||||
return (config) => {
|
return (config) => {
|
||||||
config = reactWebpackConfig(config);
|
config = reactWebpackConfig(config);
|
||||||
@ -85,11 +41,6 @@ export async function withModuleFederation(options: ModuleFederationConfig) {
|
|||||||
outputModule: true,
|
outputModule: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const mappedRemotes =
|
|
||||||
!options.remotes || options.remotes.length === 0
|
|
||||||
? {}
|
|
||||||
: mapRemotes(options.remotes, 'js', determineRemoteUrl);
|
|
||||||
|
|
||||||
config.plugins.push(
|
config.plugins.push(
|
||||||
new ModuleFederationPlugin({
|
new ModuleFederationPlugin({
|
||||||
name: options.name,
|
name: options.name,
|
||||||
|
|||||||
@ -87,6 +87,7 @@ const IGNORE_MATCHES_IN_PACKAGE = {
|
|||||||
'stylus-loader',
|
'stylus-loader',
|
||||||
'swc-loader',
|
'swc-loader',
|
||||||
'tsconfig-paths-webpack-plugin',
|
'tsconfig-paths-webpack-plugin',
|
||||||
|
'@module-federation/node',
|
||||||
],
|
],
|
||||||
rollup: ['@swc/core'],
|
rollup: ['@swc/core'],
|
||||||
storybook: [
|
storybook: [
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user