fix(angular): improve prefix handling across generators (#16913)

This commit is contained in:
Leosvel Pérez Espinosa 2023-05-10 16:18:20 +01:00 committed by GitHub
parent 20f25bfe1c
commit 284fedab46
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 72 additions and 39 deletions

View File

@ -11,7 +11,7 @@ import { E2eTestRunner, UnitTestRunner } from '../../../utils/test-runners';
import { Linter } from '@nx/linter';
import {
normalizeDirectory,
normalizePrefix,
normalizeNewProjectPrefix,
normalizeProjectName,
} from '../../utils/project';
@ -45,7 +45,7 @@ export function normalizeOptions(
? options.tags.split(',').map((s) => s.trim())
: [];
const prefix = normalizePrefix(options.prefix, npmScope);
const prefix = normalizeNewProjectPrefix(options.prefix, npmScope, 'app');
options.standaloneConfig = options.standaloneConfig ?? standaloneAsDefault;

View File

@ -64,6 +64,7 @@ export async function host(tree: Tree, options: Schema) {
skipFormat: true,
skipE2E,
e2eProjectName: skipE2E ? undefined : `${appName}-e2e`,
prefix: options.prefix,
});
let installTasks = [appInstallTask];

View File

@ -10,7 +10,7 @@ import { Schema } from '../schema';
import { NormalizedSchema } from './normalized-schema';
import { Linter } from '@nx/linter';
import { UnitTestRunner } from '../../../utils/test-runners';
import { normalizePrefix } from '../../utils/project';
import { normalizeNewProjectPrefix } from '../../utils/project';
export function normalizeOptions(host: Tree, schema: Schema): NormalizedSchema {
// Create a schema with populated default values
@ -55,7 +55,7 @@ export function normalizeOptions(host: Tree, schema: Schema): NormalizedSchema {
? options.tags.split(',').map((s) => s.trim())
: [];
const modulePath = `${projectRoot}/src/lib/${fileName}.module.ts`;
const prefix = normalizePrefix(options.prefix, npmScope);
const prefix = normalizeNewProjectPrefix(options.prefix, npmScope, 'lib');
options.standaloneConfig = options.standaloneConfig ?? standaloneAsDefault;

View File

@ -57,6 +57,7 @@ export async function remote(tree: Tree, options: Schema) {
skipE2E,
e2eProjectName: skipE2E ? undefined : `${appName}-e2e`,
standalone: options.standalone,
prefix: options.prefix,
});
let installTasks = [appInstallTask];

View File

@ -1,12 +1,6 @@
import type { Tree } from '@nx/devkit';
import {
generateFiles,
joinPathFragments,
readNxJson,
readProjectConfiguration,
} from '@nx/devkit';
import { generateFiles, joinPathFragments } from '@nx/devkit';
import { addRoute } from '../../../utils/nx-devkit/route-utils';
import type { AngularProjectConfiguration } from '../../../utils/types';
import type { Schema } from '../schema';
export function addRemoteEntry(
@ -14,11 +8,6 @@ export function addRemoteEntry(
{ appName, routing, prefix, standalone }: Schema,
appRoot: string
) {
prefix =
prefix ??
(readProjectConfiguration(tree, appName) as AngularProjectConfiguration)
?.prefix ??
readNxJson(tree).npmScope;
generateFiles(
tree,
standalone

View File

@ -5,6 +5,7 @@ export * from './change-build-target';
export * from './fix-bootstrap';
export * from './generate-config';
export * from './get-remotes-with-ports';
export * from './normalize-options';
export * from './set-tsconfig-target';
export * from './setup-host-if-dynamic';
export * from './setup-serve-target';

View File

@ -0,0 +1,14 @@
import type { Tree } from '@nx/devkit';
import { getProjectPrefix } from '../../utils/project';
import type { NormalizedOptions, Schema } from '../schema';
export function normalizeOptions(
tree: Tree,
options: Schema
): NormalizedOptions {
return {
...options,
federationType: options.federationType ?? 'static',
prefix: options.prefix ?? getProjectPrefix(tree, options.appName),
};
}

View File

@ -1,8 +1,6 @@
import { Tree } from 'nx/src/generators/tree';
import type { Tree } from '@nx/devkit';
import { joinPathFragments, readProjectConfiguration } from '@nx/devkit';
import { Schema } from '../schema';
import { readProjectConfiguration } from 'nx/src/generators/utils/project-configuration';
import { joinPathFragments } from 'nx/src/utils/path';
import { readNxJson } from '@nx/devkit';
export function removeDeadCodeFromRemote(tree: Tree, options: Schema) {
const projectName = options.appName;
@ -73,13 +71,15 @@ export class AppModule {}`
} else {
tree.delete(pathToAppComponent);
const prefix = options.prefix ?? readNxJson(tree).npmScope;
const remoteEntrySelector = `${prefix}-${projectName}-entry`;
const pathToIndexHtml = project.targets.build.options.index;
const indexContents = tree.read(pathToIndexHtml, 'utf-8');
const rootSelectorRegex = new RegExp(`${prefix}-root`, 'ig');
const rootSelectorRegex = new RegExp(
`${options.prefix || 'app'}-root`,
'ig'
);
const remoteEntrySelector = `${
options.prefix || 'app'
}-${projectName}-entry`;
const newIndexContents = indexContents.replace(
rootSelectorRegex,
remoteEntrySelector

View File

@ -1,10 +1,12 @@
type FederationType = 'static' | 'dynamic';
export interface Schema {
appName: string;
mfType: 'host' | 'remote';
port?: number;
remotes?: string[];
host?: string;
federationType?: 'static' | 'dynamic';
federationType?: FederationType;
routing?: boolean;
skipFormat?: boolean;
skipPackageJson?: boolean;
@ -13,3 +15,8 @@ export interface Schema {
standalone?: boolean;
skipE2E?: boolean;
}
export interface NormalizedOptions extends Schema {
federationType: FederationType;
prefix: string | undefined;
}

View File

@ -14,6 +14,7 @@ import {
fixBootstrap,
generateWebpackConfig,
getRemotesWithPorts,
normalizeOptions,
removeDeadCodeFromRemote,
setupHostIfDynamic,
setupServeTarget,
@ -24,17 +25,16 @@ import { getInstalledAngularVersionInfo } from '../utils/version-utils';
import { nxVersion } from '../../utils/versions';
import { lt } from 'semver';
export async function setupMf(tree: Tree, options: Schema) {
export async function setupMf(tree: Tree, rawOptions: Schema) {
const installedAngularInfo = getInstalledAngularVersionInfo(tree);
if (lt(installedAngularInfo.version, '14.1.0') && options.standalone) {
if (lt(installedAngularInfo.version, '14.1.0') && rawOptions.standalone) {
throw new Error(
`The --standalone flag is not supported in your current version of Angular (${installedAngularInfo.version}). Please update to a version of Angular that supports Standalone Components (>= 14.1.0).`
);
}
const projectConfig = readProjectConfiguration(tree, options.appName);
options.federationType = options.federationType ?? 'static';
const options = normalizeOptions(tree, rawOptions);
const projectConfig = readProjectConfiguration(tree, options.appName);
if (options.mfType === 'host') {
setupHostIfDynamic(tree, options);

View File

@ -1,4 +1,6 @@
import { names } from '@nx/devkit';
import type { Tree } from '@nx/devkit';
import { names, readNxJson, readProjectConfiguration } from '@nx/devkit';
import type { AngularProjectConfiguration } from '../../utils/types';
export function normalizeDirectory(
appName: string,
@ -16,19 +18,27 @@ export function normalizeProjectName(
return normalizeDirectory(appName, directoryName).replace(/\//g, '-');
}
export function normalizePrefix(
export function normalizeNewProjectPrefix(
prefix: string | undefined,
npmScope: string | undefined
npmScope: string | undefined,
fallbackPrefix: string
): string {
if (prefix) {
return prefix;
}
// Prefix needs to be a valid html selector, if npmScope it's not valid, we don't default
// to it and let it fall through to the Angular schematic to handle it
// https://github.com/angular/angular-cli/blob/1c634cd327e5a850553b258aa2d5e6a6b2c75c65/packages/schematics/angular/component/index.ts#L130
const htmlSelectorRegex =
/^[a-zA-Z][.0-9a-zA-Z]*(:?-[a-zA-Z][.0-9a-zA-Z]*)*$/;
if (prefix) {
if (!htmlSelectorRegex.test(prefix)) {
throw new Error(
'The provided "prefix" is invalid. The prefix must start with a letter, and must contain only alphanumeric characters or dashes. When adding a dash the segment after the dash must also start with a letter.'
);
}
return prefix;
}
if (npmScope && !htmlSelectorRegex.test(npmScope)) {
throw new Error(`The "--prefix" option was not provided, therefore attempted to use the "npmScope" defined in "nx.json" to set the application's selector prefix, but it is invalid.
@ -41,5 +51,15 @@ If you encountered this error when creating a new Nx Workspace, the workspace na
Valid selector prefixes must start with a letter, and must contain only alphanumeric characters or dashes. When adding a dash the segment after the dash must also start with a letter.`);
}
return npmScope || 'app';
return npmScope || fallbackPrefix;
}
export function getProjectPrefix(
tree: Tree,
project: string
): string | undefined {
return (
(readProjectConfiguration(tree, project) as AngularProjectConfiguration)
.prefix ?? readNxJson(tree).npmScope
);
}