Skip to content

Commit

Permalink
fix(react): use normalized app name in host/remote generators (#9909)
Browse files Browse the repository at this point in the history
  • Loading branch information
jaysoo authored Apr 21, 2022
1 parent 81af0b4 commit 7913f31
Show file tree
Hide file tree
Showing 15 changed files with 151 additions and 52 deletions.
81 changes: 75 additions & 6 deletions e2e/react/src/react.module-federation.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { stripIndents } from '@nrwl/devkit';
import {
checkFilesExist,
killPorts,
killPort,
newProject,
readProjectConfig,
runCLI,
Expand All @@ -21,8 +21,12 @@ describe('React Module Federation', () => {
const remote2 = uniq('remote2');
const remote3 = uniq('remote3');

runCLI(`generate @nrwl/react:host ${shell} --style=css --no-interactive`);
runCLI(
`generate @nrwl/react:host ${shell} --style=css --remotes=${remote1},${remote2} --no-interactive`
`generate @nrwl/react:remote ${remote1} --style=css --host=${shell} --no-interactive`
);
runCLI(
`generate @nrwl/react:remote ${remote2} --style=css --host=${shell} --no-interactive`
);
runCLI(
`generate @nrwl/react:remote ${remote3} --style=css --host=${shell} --no-interactive`
Expand All @@ -46,9 +50,7 @@ describe('React Module Federation', () => {
module.exports = withModuleFederation({
...moduleFederationConfig,
remotes: [
['${remote1}', '${remote1}@http://localhost:${readPort(
remote1
)}/remoteEntry.js'],
'${remote1}',
['${remote2}', 'http://localhost:${readPort(
remote2
)}/remoteEntry.js'],
Expand Down Expand Up @@ -89,11 +91,78 @@ describe('React Module Federation', () => {

const e2eResults = runCLI(`e2e ${shell}-e2e --no-watch`);
expect(e2eResults).toContain('All specs passed!');
expect(await killPorts()).toBeTruthy();
expect(
await killPorts([
readPort(shell),
readPort(remote1),
readPort(remote2),
readPort(remote3),
])
).toBeTruthy();
}, 500_000);

// TODO(jack): Fix port taken issue in CI then enable test again
// it('should support nested directories', async () => {
// const shell = uniq('shell');
// const remote1 = uniq('remote1');
// const remote2 = uniq('remote2');
// const remote3 = uniq('remote3');
//
// runCLI(
// `generate @nrwl/react:host ${shell} --style=css --remotes=${remote1},${remote2},${remote3} --directory=test --no-interactive`
// );
//
// await expect(runCLIAsync(`test test-${shell}`)).resolves.toMatchObject({
// combinedOutput: expect.stringContaining('Test Suites: 1 passed, 1 total'),
// });
//
// updateFile(
// `apps/test/${shell}-e2e/src/integration/app.spec.ts`,
// stripIndents`
// import { getGreeting } from '../support/app.po';
//
// describe('shell app', () => {
// it('should display welcome message', () => {
// cy.visit('/')
// getGreeting().contains('Welcome test-${shell}');
// });
//
// it('should load remote 1', () => {
// cy.visit('/test-${remote1}')
// getGreeting().contains('Welcome test-${remote1}');
// });
//
// it('should load remote 2', () => {
// cy.visit('/test-${remote2}')
// getGreeting().contains('Welcome test-${remote2}');
// });
//
// it('should load remote 3', () => {
// cy.visit('/test-${remote3}')
// getGreeting().contains('Welcome test-${remote3}');
// });
// });
// `
// );
//
// const e2eResults = runCLI(`e2e test-${shell}-e2e --no-watch`);
// expect(e2eResults).toContain('All specs passed!');
// expect(
// await killPorts([
// readPort(`test-${shell}`),
// readPort(`test-${remote1}`),
// readPort(`test-${remote2}`),
// readPort(`test-${remote3}`),
// ])
// ).toBeTruthy();
// }, 500_000);

function readPort(appName: string): number {
const config = readProjectConfig(appName);
return config.targets.serve.options.port;
}
});

function killPorts(ports: number[]): Promise<boolean[]> {
return Promise.all(ports.map((p) => killPort(p)));
}
2 changes: 1 addition & 1 deletion e2e/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ export function newProject({

const KILL_PORT_DELAY = 5000;

async function killPort(port: number): Promise<boolean> {
export async function killPort(port: number): Promise<boolean> {
if (await portCheck(port)) {
try {
logInfo(`Attempting to close port ${port}`);
Expand Down
17 changes: 12 additions & 5 deletions packages/react/src/generators/application/lib/normalize-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,22 @@ import { assertValidStyle } from '../../../utils/assertion';
import { getWorkspaceLayout, names, normalizePath, Tree } from '@nrwl/devkit';
import { findFreePort } from './find-free-port';

export function normalizeDirectory(options: Schema) {
return options.directory
? `${names(options.directory).fileName}/${names(options.name).fileName}`
: names(options.name).fileName;
}

export function normalizeProjectName(options: Schema) {
return normalizeDirectory(options).replace(new RegExp('/', 'g'), '-');
}

export function normalizeOptions(
host: Tree,
options: Schema
): NormalizedSchema {
const appDirectory = options.directory
? `${names(options.directory).fileName}/${names(options.name).fileName}`
: names(options.name).fileName;

const appProjectName = appDirectory.replace(new RegExp('/', 'g'), '-');
const appDirectory = normalizeDirectory(options);
const appProjectName = normalizeProjectName(options);
const e2eProjectName = `${appProjectName}-e2e`;

const { appsDir } = getWorkspaceLayout(host);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as React from 'react';
import NxWelcome from "./nx-welcome";
<% if (remotes.length > 0) { %>
import { Link, Route, Routes } from 'react-router-dom';

<% if (remotes.length > 0) { %>
<% remotes.forEach(function(r) { %>
const <%= r.className %> = React.lazy(() => import('<%= r.fileName %>/Module'));
<% }); %>
Expand Down
6 changes: 5 additions & 1 deletion packages/react/src/generators/host/host.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { formatFiles, Tree } from '@nrwl/devkit';

import applicationGenerator from '../application/application';
import { normalizeOptions } from '../application/lib/normalize-options';
import {
normalizeOptions,
normalizeProjectName,
} from '../application/lib/normalize-options';
import { updateModuleFederationProject } from '../../rules/update-module-federation-project';
import { addModuleFederationFiles } from './lib/add-module-federation-files';
import { updateModuleFederationE2eProject } from './lib/update-module-federation-e2e-project';
Expand All @@ -25,6 +28,7 @@ export async function hostGenerator(host: Tree, schema: Schema) {
remotesWithPorts.push({ name: remote, port: remotePort });
await remoteGenerator(host, {
name: remote,
directory: options.directory,
style: options.style,
skipFormat: options.skipFormat,
unitTestRunner: options.unitTestRunner,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { NormalizedSchema } from '../schema';
import { generateFiles, names } from '@nrwl/devkit';
import { join } from 'path';
import { normalizeProjectName } from '../../application/lib/normalize-options';

export function addModuleFederationFiles(
host,
Expand All @@ -11,10 +12,13 @@ export function addModuleFederationFiles(
...names(options.name),
...options,
tmpl: '',
remotes: defaultRemoteManifest.map(({ name, port }) => ({
...names(name),
port,
})),
remotes: defaultRemoteManifest.map(({ name, port }) => {
const remote = normalizeProjectName({ ...options, name });
return {
...names(remote),
port,
};
}),
};

// Module federation requires bootstrap code to be dynamically imported.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@ export function updateModuleFederationE2eProject(
host: Tree,
options: NormalizedSchema
) {
const e2eName = `${options.name}-e2e`;
try {
let projectConfig = readProjectConfiguration(host, e2eName);
let projectConfig = readProjectConfiguration(host, options.e2eProjectName);
projectConfig.targets.e2e.options = {
...projectConfig.targets.e2e.options,
baseUrl: 'http://localhost:4200',
baseUrl: `http://localhost:${options.devServerPort}`,
};
updateProjectConfiguration(host, e2eName, projectConfig);
updateProjectConfiguration(host, options.e2eProjectName, projectConfig);
} catch {
// nothing
}
Expand Down
2 changes: 2 additions & 0 deletions packages/react/src/generators/host/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,7 @@ export interface Schema {
}

export interface NormalizedSchema extends Schema {
projectName: string;
appProjectRoot: string;
e2eProjectName: string;
}
29 changes: 16 additions & 13 deletions packages/react/src/module-federation/ast-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,24 @@ export function addRemoteToConfig(
const arrayExpression =
remotesAssignment.initializer as ts.ArrayLiteralExpression;

return arrayExpression.elements
? [
{
if (!arrayExpression.elements) return [];

const lastElement =
arrayExpression.elements[arrayExpression.elements.length - 1];
return [
lastElement
? {
type: ChangeType.Insert,
index:
arrayExpression.elements[arrayExpression.elements.length - 1].end,
index: lastElement.end,
text: `,`,
},
{
type: ChangeType.Insert,
index: remotesAssignment.end - 1,
text: `'${app}',\n`,
},
]
: [];
}
: null,
{
type: ChangeType.Insert,
index: remotesAssignment.end - 1,
text: `'${app}',\n`,
},
].filter(Boolean) as StringChange[];
}

const binaryExpressions = findNodes(
Expand Down
15 changes: 10 additions & 5 deletions packages/react/src/module-federation/with-module-federation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ import {
} from '@nrwl/workspace/src/utilities/typescript';
import { ParsedCommandLine } from 'typescript';
import { readWorkspaceJson } from 'nx/src/project-graph/file-utils';
import ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
import { ModuleFederationConfig, Remotes } from './models';
import ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');

function recursivelyResolveWorkspaceDependents(
projectGraph: ProjectGraph<any>,
Expand Down Expand Up @@ -139,7 +139,7 @@ function determineRemoteUrl(remote: string) {

const host = serveTarget.options?.host ?? '//localhost';
const port = serveTarget.options?.port ?? 4201;
return `${remote}@${
return `${
host.endsWith('/') ? host.slice(0, -1) : host
}:${port}/remoteEntry.js`;
}
Expand All @@ -150,9 +150,6 @@ function mapRemotes(remotes: Remotes) {
for (const remote of remotes) {
if (Array.isArray(remote)) {
let [remoteName, remoteLocation] = remote;
if (!remoteLocation.includes('@')) {
remoteLocation = `${remoteName}@${remoteLocation}`;
}
if (!remoteLocation.match(/remoteEntry\.(js|mjs)$/)) {
remoteLocation = `${
remoteLocation.endsWith('/')
Expand Down Expand Up @@ -216,6 +213,11 @@ export async function withModuleFederation(options: ModuleFederationConfig) {
minimize: false,
};

config.experiments = {
...config.experiments,
outputModule: true,
};

const mappedRemotes =
!options.remotes || options.remotes.length === 0
? {}
Expand All @@ -224,6 +226,9 @@ export async function withModuleFederation(options: ModuleFederationConfig) {
config.plugins.push(
new ModuleFederationPlugin({
name: options.name,
library: {
type: 'module',
},
filename: 'remoteEntry.js',
exposes: options.exposes,
remotes: mappedRemotes,
Expand Down
18 changes: 11 additions & 7 deletions packages/react/src/rules/update-module-federation-project.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import {
Tree,
readProjectConfiguration,
Tree,
updateProjectConfiguration,
} from '@nrwl/devkit';

export function updateModuleFederationProject(
host: Tree,
options: { name: string; appProjectRoot: string; devServerPort?: number }
options: {
projectName: string;
appProjectRoot: string;
devServerPort?: number;
}
) {
const projectConfig = readProjectConfiguration(host, options.name);
const projectConfig = readProjectConfiguration(host, options.projectName);

projectConfig.targets.build.options = {
...projectConfig.targets.build.options,
Expand All @@ -30,18 +34,18 @@ export function updateModuleFederationProject(
executor: '@nrwl/web:file-server',
defaultConfiguration: 'development',
options: {
buildTarget: `${options.name}:build`,
buildTarget: `${options.projectName}:build`,
port: options.devServerPort,
},
configurations: {
development: {
buildTarget: `${options.name}:build:development`,
buildTarget: `${options.projectName}:build:development`,
},
production: {
buildTarget: `${options.name}:build:production`,
buildTarget: `${options.projectName}:build:production`,
},
},
};

updateProjectConfiguration(host, options.name, projectConfig);
updateProjectConfiguration(host, options.projectName, projectConfig);
}
2 changes: 1 addition & 1 deletion packages/web/src/executors/file-server/file-server.impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { platform } from 'os';
const pmCmd = platform() === 'win32' ? `npx.cmd` : 'npx';

function getHttpServerArgs(options: Schema) {
const args = ['-c-1'];
const args = ['-c-1', '--cors'];
if (options.port) {
args.push(`-p=${options.port}`);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,13 @@ export async function augmentIndexHtml(

if (isNoModuleType && !isModuleType) {
attrs.push('nomodule', 'defer');
} else if (isModuleType && !isNoModuleType) {
} else if (isModuleType) {
attrs.push('type="module"');
} else {
attrs.push('defer');
}
} else {
attrs.push('defer');
attrs.push('type="module"');
}

if (sri) {
Expand Down
Loading

0 comments on commit 7913f31

Please sign in to comment.