Skip to content

Commit

Permalink
fix(module-federation): ensure targetDefaults for module federation e…
Browse files Browse the repository at this point in the history
…xecutors are setup correctly (#22282)
  • Loading branch information
Coly010 committed Mar 12, 2024
1 parent b6cd196 commit 81df848
Show file tree
Hide file tree
Showing 10 changed files with 428 additions and 2 deletions.
6 changes: 6 additions & 0 deletions packages/angular/migrations.json
Expand Up @@ -371,6 +371,12 @@
},
"description": "Update the @angular/cli package version to ~17.2.0.",
"factory": "./src/migrations/update-18-1-0/update-angular-cli"
},
"fix-target-defaults-for-webpack-browser": {
"cli": "nx",
"version": "18.1.1-beta.0",
"description": "Ensure targetDefaults inputs for task hashing when '@nx/angular:webpack-browser' is used are correct for Module Federation.",
"factory": "./src/migrations/update-18-1-1/fix-target-defaults-inputs"
}
},
"packageJsonUpdates": {
Expand Down
Expand Up @@ -7,7 +7,10 @@ export function addMfEnvToTargetDefaultInputs(tree: Tree) {

nxJson.targetDefaults ??= {};
nxJson.targetDefaults[webpackExecutor] ??= {};
nxJson.targetDefaults[webpackExecutor].inputs ??= [];
nxJson.targetDefaults[webpackExecutor].inputs ??= [
'production',
'^production',
];

let mfEnvVarExists = false;
for (const input of nxJson.targetDefaults[webpackExecutor].inputs) {
Expand Down
Expand Up @@ -26,6 +26,8 @@ describe('addMfEnvVarToTargetDefaults', () => {
{
"@nx/angular:webpack-browser": {
"inputs": [
"production",
"^production",
{
"env": "NX_MF_DEV_SERVER_STATIC_REMOTES",
},
Expand Down
@@ -0,0 +1,127 @@
import fixTargetDefaultInputs from './fix-target-defaults-inputs';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { addProjectConfiguration, readNxJson, updateNxJson } from '@nx/devkit';

describe('fixTargetDefaultsInputs', () => {
it('should add the executor and input when it does not exist', async () => {
// ARRANGE
const tree = createTreeWithEmptyWorkspace();
addProjectConfiguration(tree, 'test', {
root: '',
targets: {
build: {
executor: '@nx/angular:webpack-browser',
},
},
});

tree.write('module-federation.config.ts', '');

// ACT
await fixTargetDefaultInputs(tree);

// ASSERT
const nxJson = readNxJson(tree);
expect(nxJson.targetDefaults).toMatchInlineSnapshot(`
{
"@nx/angular:webpack-browser": {
"inputs": [
"production",
"^production",
{
"env": "NX_MF_DEV_SERVER_STATIC_REMOTES",
},
],
},
"build": {
"cache": true,
},
"lint": {
"cache": true,
},
}
`);
});

it('should not add the executor and input when no project uses it', async () => {
// ARRANGE
const tree = createTreeWithEmptyWorkspace();
addProjectConfiguration(tree, 'test', {
root: '',
targets: {
build: {
executor: '@nx/angular:module-federation-dev-server',
},
},
});

// ACT
await fixTargetDefaultInputs(tree);

// ASSERT
const nxJson = readNxJson(tree);
expect(nxJson.targetDefaults).toMatchInlineSnapshot(`
{
"build": {
"cache": true,
},
"lint": {
"cache": true,
},
}
`);
});

it('should update the executor and input target default when it already exists', async () => {
// ARRANGE
const tree = createTreeWithEmptyWorkspace();
addProjectConfiguration(tree, 'test', {
root: '',
targets: {
build: {
executor: '@nx/angular:webpack-browser',
},
},
});
tree.write('module-federation.config.ts', '');

let nxJson = readNxJson(tree);
nxJson = {
...nxJson,
targetDefaults: {
...nxJson.targetDefaults,
['@nx/angular:webpack-browser']: {
inputs: ['^build'],
},
},
};

updateNxJson(tree, nxJson);

// ACT
await fixTargetDefaultInputs(tree);

// ASSERT
nxJson = readNxJson(tree);
expect(nxJson.targetDefaults).toMatchInlineSnapshot(`
{
"@nx/angular:webpack-browser": {
"inputs": [
"^build",
"production",
"^production",
{
"env": "NX_MF_DEV_SERVER_STATIC_REMOTES",
},
],
},
"build": {
"cache": true,
},
"lint": {
"cache": true,
},
}
`);
});
});
@@ -0,0 +1,75 @@
import {
getProjects,
type Tree,
type ProjectConfiguration,
joinPathFragments,
formatFiles,
readNxJson,
updateNxJson,
} from '@nx/devkit';

export default async function (tree: Tree) {
if (!isWebpackBrowserUsed(tree)) {
return;
}
ensureTargetDefaultsContainProductionInputs(tree);

await formatFiles(tree);
}

function ensureTargetDefaultsContainProductionInputs(tree: Tree) {
const nxJson = readNxJson(tree);
const webpackExecutor = '@nx/angular:webpack-browser';
const mfEnvVar = 'NX_MF_DEV_SERVER_STATIC_REMOTES';

nxJson.targetDefaults[webpackExecutor] ??= {};

nxJson.targetDefaults[webpackExecutor].inputs ??= [
'production',
'^production',
{ env: mfEnvVar },
];

if (!nxJson.targetDefaults[webpackExecutor].inputs.includes('production')) {
nxJson.targetDefaults[webpackExecutor].inputs.push('production');
}

if (!nxJson.targetDefaults[webpackExecutor].inputs.includes('^production')) {
nxJson.targetDefaults[webpackExecutor].inputs.push('^production');
}

let mfEnvVarExists = false;
for (const input of nxJson.targetDefaults[webpackExecutor].inputs) {
if (typeof input === 'object' && input['env'] === mfEnvVar) {
mfEnvVarExists = true;
break;
}
}

if (!mfEnvVarExists) {
nxJson.targetDefaults[webpackExecutor].inputs.push({ env: mfEnvVar });
}

updateNxJson(tree, nxJson);
}

function isWebpackBrowserUsed(tree: Tree) {
const projects = getProjects(tree);
for (const project of projects.values()) {
const targets = project.targets || {};
for (const [_, target] of Object.entries(targets)) {
if (
target.executor === '@nx/angular:webpack-browser' &&
(tree.exists(
joinPathFragments(project.root, 'module-federation.config.ts')
) ||
tree.exists(
joinPathFragments(project.root, 'module-federation.config.js')
))
) {
return true;
}
}
}
return false;
}
6 changes: 6 additions & 0 deletions packages/react/migrations.json
Expand Up @@ -53,6 +53,12 @@
"version": "18.0.0-beta.0",
"description": "Add NX_MF_DEV_SERVER_STATIC_REMOTES to inputs for task hashing when '@nx/webpack:webpack' is used for Module Federation.",
"factory": "./src/migrations/update-18-0-0/add-mf-env-var-to-target-defaults"
},
"fix-target-defaults-for-webpack": {
"cli": "nx",
"version": "18.1.1-beta.0",
"description": "Ensure targetDefaults inputs for task hashing when '@nx/webpack:webpack' is used are correct for Module Federation.",
"factory": "./src/migrations/update-18-1-1/fix-target-defaults-inputs"
}
},
"packageJsonUpdates": {
Expand Down
Expand Up @@ -25,6 +25,8 @@ describe('addMfEnvVarToTargetDefaults', () => {
{
"@nx/webpack:webpack": {
"inputs": [
"production",
"^production",
{
"env": "NX_MF_DEV_SERVER_STATIC_REMOTES",
},
Expand Down
@@ -0,0 +1,127 @@
import fixTargetDefaultsInputs from './fix-target-defaults-inputs';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { addProjectConfiguration, readNxJson, updateNxJson } from '@nx/devkit';

describe('fixTargetDefaultsInputs', () => {
it('should add the executor and input when it does not exist', async () => {
// ARRANGE
const tree = createTreeWithEmptyWorkspace();
addProjectConfiguration(tree, 'test', {
root: '',
targets: {
build: {
executor: '@nx/webpack:webpack',
},
},
});
tree.write('module-federation.config.ts', '');

// ACT
await fixTargetDefaultsInputs(tree);

// ASSERT
const nxJson = readNxJson(tree);
expect(nxJson.targetDefaults).toMatchInlineSnapshot(`
{
"@nx/webpack:webpack": {
"inputs": [
"production",
"^production",
{
"env": "NX_MF_DEV_SERVER_STATIC_REMOTES",
},
],
},
"build": {
"cache": true,
},
"lint": {
"cache": true,
},
}
`);
});

it('should not add the executor and input when no project uses it', async () => {
// ARRANGE
const tree = createTreeWithEmptyWorkspace();
addProjectConfiguration(tree, 'test', {
root: '',
targets: {
build: {
executor: '@nx/angular:module-federation-dev-server',
},
},
});

// ACT
await fixTargetDefaultsInputs(tree);

// ASSERT
const nxJson = readNxJson(tree);
expect(nxJson.targetDefaults).toMatchInlineSnapshot(`
{
"build": {
"cache": true,
},
"lint": {
"cache": true,
},
}
`);
});

it('should update the executor and input target default when it already exists', async () => {
// ARRANGE
const tree = createTreeWithEmptyWorkspace();
addProjectConfiguration(tree, 'test', {
root: '',
targets: {
build: {
executor: '@nx/webpack:webpack',
},
},
});

tree.write('module-federation.config.ts', '');

let nxJson = readNxJson(tree);
nxJson = {
...nxJson,
targetDefaults: {
...nxJson.targetDefaults,
['@nx/webpack:webpack']: {
inputs: ['^build'],
},
},
};

updateNxJson(tree, nxJson);

// ACT
await fixTargetDefaultsInputs(tree);

// ASSERT
nxJson = readNxJson(tree);
expect(nxJson.targetDefaults).toMatchInlineSnapshot(`
{
"@nx/webpack:webpack": {
"inputs": [
"^build",
"production",
"^production",
{
"env": "NX_MF_DEV_SERVER_STATIC_REMOTES",
},
],
},
"build": {
"cache": true,
},
"lint": {
"cache": true,
},
}
`);
});
});

0 comments on commit 81df848

Please sign in to comment.