Skip to content

Commit

Permalink
feat(module-federation): add nx-runtime-library-control-plugin (#26816)
Browse files Browse the repository at this point in the history
- feat(module-federation): use @module-federation/enhanced for
withModuleFederation
- feat(module-federation): expose API for users to override module
federation plugin options
- fix(module-federation): angular mf ssr projects should not create
vendor chunks
- feat(module-federation): add nx-runtime-library-control-plugin

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->
A common occurrence when working with NX Module Federation is that a
shared library may get resolved from a static remote.
Any changes to the shared lib are therefore not reflected in the dev
server.


## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
Add the `nx-runtime-library-control-plugin` to ensure that shared
libraries are shared from a remote that is served via
webpack-dev-server.

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #11615
  • Loading branch information
Coly010 committed Jul 18, 2024
1 parent 7f53e56 commit 483bcf3
Show file tree
Hide file tree
Showing 19 changed files with 273 additions and 94 deletions.
2 changes: 1 addition & 1 deletion e2e/angular/src/projects.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ describe('Angular Projects', () => {
console.log(
`The current es2015 bundle size is ${es2015BundleSize / 1000} KB`
);
expect(es2015BundleSize).toBeLessThanOrEqual(220000);
expect(es2015BundleSize).toBeLessThanOrEqual(221000);

// check unit tests
runCLI(
Expand Down
3 changes: 2 additions & 1 deletion packages/angular/ng-package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
"magic-string",
"enquirer",
"find-cache-dir",
"piscina"
"piscina",
"webpack"
],
"keepLifecycleScripts": true
}
1 change: 1 addition & 0 deletions packages/angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"semver": "^7.5.3",
"tslib": "^2.3.0",
"webpack-merge": "^5.8.0",
"webpack": "^5.88.0",
"@module-federation/enhanced": "~0.2.3",
"@nx/devkit": "file:../devkit",
"@nx/js": "file:../js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ export function executeModuleFederationDevSSRBuilder(
? options.devRemotes
: [options.devRemotes];

// Set NX_MF_DEV_REMOTES for the Nx Runtime Library Control Plugin
process.env.NX_MF_DEV_REMOTES = JSON.stringify(devServeRemotes);

validateDevRemotes({ devRemotes: devServeRemotes }, workspaceProjects);

const remotesToSkip = new Set(options.skipRemotes ?? []);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ export async function* moduleFederationDevServerExecutor(
pathToManifestFile
);

// Set NX_MF_DEV_REMOTES for the Nx Runtime Library Control Plugin
process.env.NX_MF_DEV_REMOTES = JSON.stringify(
remotes.devRemotes.map((r) => (typeof r === 'string' ? r : r.remoteName))
);

if (remotes.devRemotes.length > 0 && !schema.staticRemotesPort) {
options.staticRemotesPort = options.devRemotes.reduce((portToUse, r) => {
const remoteName = typeof r === 'string' ? r : r.remoteName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { type Tree, readNxJson, updateNxJson } from '@nx/devkit';
export function addMfEnvToTargetDefaultInputs(tree: Tree) {
const nxJson = readNxJson(tree);
const webpackExecutor = '@nx/angular:webpack-browser';
const mfEnvVar = 'NX_MF_DEV_SERVER_STATIC_REMOTES';
const mfEnvVar = 'NX_MF_DEV_REMOTES';

nxJson.targetDefaults ??= {};
nxJson.targetDefaults[webpackExecutor] ??= {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ describe('addMfEnvVarToTargetDefaults', () => {
"production",
"^production",
{
"env": "NX_MF_DEV_SERVER_STATIC_REMOTES",
"env": "NX_MF_DEV_REMOTES",
},
],
},
Expand Down Expand Up @@ -109,7 +109,7 @@ describe('addMfEnvVarToTargetDefaults', () => {
"inputs": [
"^build",
{
"env": "NX_MF_DEV_SERVER_STATIC_REMOTES",
"env": "NX_MF_DEV_REMOTES",
},
],
},
Expand Down
105 changes: 64 additions & 41 deletions packages/angular/src/utils/mf/with-module-federation-ssr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,52 +11,75 @@ export async function withModuleFederationForSSR(
if (global.NX_GRAPH_CREATION) {
return (config) => config;
}

const { sharedLibraries, sharedDependencies, mappedRemotes } =
await getModuleFederationConfig(options, {
isServer: true,
});

return (config) => ({
...(config ?? {}),
target: false,
output: {
...(config.output ?? {}),
uniqueName: options.name,
},
optimization: {
...(config.optimization ?? {}),
runtimeChunk: false,
},
resolve: {
...(config.resolve ?? {}),
alias: {
...(config.resolve?.alias ?? {}),
...sharedLibraries.getAliases(),
return (config) => {
const updatedConfig = {
...(config ?? {}),
target: false,
output: {
...(config.output ?? {}),
uniqueName: options.name,
},
},
plugins: [
...(config.plugins ?? []),
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,
/**
* Apply user-defined config override
*/
...(configOverride ? configOverride : {}),
optimization: {
...(config.optimization ?? {}),
runtimeChunk: false,
},
resolve: {
...(config.resolve ?? {}),
alias: {
...(config.resolve?.alias ?? {}),
...sharedLibraries.getAliases(),
},
{}
),
sharedLibraries.getReplacementPlugin(),
],
});
},
plugins: [
...(config.plugins ?? []),
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,
/**
* Apply user-defined config override
*/
...(configOverride ? configOverride : {}),
runtimePlugins:
process.env.NX_MF_DEV_REMOTES &&
!options.disableNxRuntimeLibraryControlPlugin
? [
...(configOverride?.runtimePlugins ?? []),
require.resolve(
'@nx/webpack/src/utils/module-federation/plugins/runtime-library-control.plugin.js'
),
]
: configOverride?.runtimePlugins,
},
{}
),
sharedLibraries.getReplacementPlugin(),
],
};

// The env var is only set from the module-federation-dev-server
// Attach the runtime plugin
updatedConfig.plugins.push(
new (require('webpack').DefinePlugin)({
'process.env.NX_MF_DEV_REMOTES': process.env.NX_MF_DEV_REMOTES,
})
);

return updatedConfig;
};
}
105 changes: 64 additions & 41 deletions packages/angular/src/utils/mf/with-module-federation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,50 +12,73 @@ export async function withModuleFederation(
if (global.NX_GRAPH_CREATION) {
return (config) => config;
}

const { sharedLibraries, sharedDependencies, mappedRemotes } =
await getModuleFederationConfig(options);

return (config) => ({
...(config ?? {}),
output: {
...(config.output ?? {}),
uniqueName: options.name,
publicPath: 'auto',
},
optimization: {
...(config.optimization ?? {}),
runtimeChunk: false,
},
resolve: {
...(config.resolve ?? {}),
alias: {
...(config.resolve?.alias ?? {}),
...sharedLibraries.getAliases(),
return (config) => {
const updatedConfig = {
...(config ?? {}),
output: {
...(config.output ?? {}),
uniqueName: options.name,
publicPath: 'auto',
},
},
experiments: {
...(config.experiments ?? {}),
outputModule: true,
},
plugins: [
...(config.plugins ?? []),
new ModuleFederationPlugin({
name: options.name,
filename: 'remoteEntry.mjs',
exposes: options.exposes,
remotes: mappedRemotes,
shared: {
...sharedDependencies,
},
library: {
type: 'module',
optimization: {
...(config.optimization ?? {}),
runtimeChunk: false,
},
resolve: {
...(config.resolve ?? {}),
alias: {
...(config.resolve?.alias ?? {}),
...sharedLibraries.getAliases(),
},
/**
* Apply user-defined config override
*/
...(configOverride ? configOverride : {}),
}),
sharedLibraries.getReplacementPlugin(),
],
});
},
experiments: {
...(config.experiments ?? {}),
outputModule: true,
},
plugins: [
...(config.plugins ?? []),
new ModuleFederationPlugin({
name: options.name,
filename: 'remoteEntry.mjs',
exposes: options.exposes,
remotes: mappedRemotes,
shared: {
...sharedDependencies,
},
library: {
type: 'module',
},
/**
* Apply user-defined config override
*/
...(configOverride ? configOverride : {}),
runtimePlugins:
process.env.NX_MF_DEV_REMOTES &&
!options.disableNxRuntimeLibraryControlPlugin
? [
...(configOverride?.runtimePlugins ?? []),
require.resolve(
'@nx/webpack/src/utils/module-federation/plugins/runtime-library-control.plugin.js'
),
]
: configOverride?.runtimePlugins,
}),
sharedLibraries.getReplacementPlugin(),
],
};

// The env var is only set from the module-federation-dev-server
// Attach the runtime plugin
updatedConfig.plugins.push(
new (require('webpack').DefinePlugin)({
'process.env.NX_MF_DEV_REMOTES': process.env.NX_MF_DEV_REMOTES,
})
);

return updatedConfig;
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,11 @@ export default async function* moduleFederationDevServer(
pathToManifestFile
);

// Set NX_MF_DEV_REMOTES for the Nx Runtime Library Control Plugin
process.env.NX_MF_DEV_REMOTES = JSON.stringify(
remotes.devRemotes.map((r) => (typeof r === 'string' ? r : r.remoteName))
);

if (remotes.devRemotes.length > 0 && !initialStaticRemotesPorts) {
options.staticRemotesPort = options.devRemotes.reduce((portToUse, r) => {
const remoteName = typeof r === 'string' ? r : r.remoteName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ export default async function* moduleFederationSsrDevServer(
? options.devRemotes
: [options.devRemotes];

// Set NX_MF_DEV_REMOTES for the Nx Runtime Library Control Plugin
process.env.NX_MF_DEV_REMOTES = JSON.stringify(devServeApps);

for (const app of knownRemotes) {
const [appName] = Array.isArray(app) ? app : [app];
const isDev = devServeApps.includes(appName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe('addMfEnvVarToTargetDefaults', () => {
"production",
"^production",
{
"env": "NX_MF_DEV_SERVER_STATIC_REMOTES",
"env": "NX_MF_DEV_REMOTES",
},
],
},
Expand Down Expand Up @@ -109,7 +109,7 @@ describe('addMfEnvVarToTargetDefaults', () => {
"inputs": [
"^build",
{
"env": "NX_MF_DEV_SERVER_STATIC_REMOTES",
"env": "NX_MF_DEV_REMOTES",
},
],
},
Expand Down
18 changes: 18 additions & 0 deletions packages/react/src/module-federation/with-module-federation-ssr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,30 @@ export async function withModuleFederationForSSR(
* Apply user-defined config overrides
*/
...(configOverride ? configOverride : {}),
runtimePlugins:
process.env.NX_MF_DEV_REMOTES &&
!options.disableNxRuntimeLibraryControlPlugin
? [
...(configOverride?.runtimePlugins ?? []),
require.resolve(
'@nx/webpack/src/utils/module-federation/plugins/runtime-library-control.plugin.js'
),
]
: configOverride?.runtimePlugins,
},
{}
),
sharedLibraries.getReplacementPlugin()
);

// The env var is only set from the module-federation-dev-server
// Attach the runtime plugin
config.plugins.push(
new (require('webpack').DefinePlugin)({
'process.env.NX_MF_DEV_REMOTES': process.env.NX_MF_DEV_REMOTES,
})
);

return config;
};
}
Loading

0 comments on commit 483bcf3

Please sign in to comment.