This PR adds the ability to set the port of the React application when using the generator. e.g. ```shell npx nx g @nx/react:app --port 8080 ``` This is useful when generating multiple apps and then running them in parallel.
241 lines
7.6 KiB
TypeScript
241 lines
7.6 KiB
TypeScript
import {
|
|
addProjectConfiguration,
|
|
ensurePackage,
|
|
GeneratorCallback,
|
|
getPackageManagerCommand,
|
|
joinPathFragments,
|
|
Tree,
|
|
writeJson,
|
|
} from '@nx/devkit';
|
|
import { webStaticServeGenerator } from '@nx/web';
|
|
|
|
import { nxVersion } from '../../../utils/versions';
|
|
import { hasWebpackPlugin } from '../../../utils/has-webpack-plugin';
|
|
import { hasVitePlugin } from '../../../utils/has-vite-plugin';
|
|
import { hasRspackPlugin } from '../../../utils/has-rspack-plugin';
|
|
import { hasRsbuildPlugin } from '../../../utils/has-rsbuild-plugin';
|
|
import { NormalizedSchema } from '../schema';
|
|
import { E2EWebServerDetails } from '@nx/devkit/src/generators/e2e-web-server-info-utils';
|
|
import type { PackageJson } from 'nx/src/utils/package-json';
|
|
|
|
export async function addE2e(
|
|
tree: Tree,
|
|
options: NormalizedSchema
|
|
): Promise<GeneratorCallback> {
|
|
const hasNxBuildPlugin =
|
|
(options.bundler === 'webpack' && hasWebpackPlugin(tree)) ||
|
|
(options.bundler === 'rspack' && hasRspackPlugin(tree)) ||
|
|
(options.bundler === 'rsbuild' &&
|
|
(await hasRsbuildPlugin(tree, options.appProjectRoot))) ||
|
|
(options.bundler === 'vite' && hasVitePlugin(tree));
|
|
|
|
let e2eWebServerInfo: E2EWebServerDetails = {
|
|
e2eWebServerAddress: `http://localhost:${options.devServerPort ?? 4200}`,
|
|
e2eWebServerCommand: `${getPackageManagerCommand().exec} nx run ${
|
|
options.projectName
|
|
}:serve`,
|
|
e2eCiWebServerCommand: `${getPackageManagerCommand().exec} nx run ${
|
|
options.projectName
|
|
}:serve-static`,
|
|
e2eCiBaseUrl: `http://localhost:${options.port ?? 4300}`,
|
|
e2eDevServerTarget: `${options.projectName}:serve`,
|
|
};
|
|
|
|
if (options.bundler === 'webpack') {
|
|
const { getWebpackE2EWebServerInfo } = ensurePackage<
|
|
typeof import('@nx/webpack')
|
|
>('@nx/webpack', nxVersion);
|
|
e2eWebServerInfo = await getWebpackE2EWebServerInfo(
|
|
tree,
|
|
options.projectName,
|
|
joinPathFragments(
|
|
options.appProjectRoot,
|
|
`webpack.config.${options.js ? 'js' : 'ts'}`
|
|
),
|
|
options.addPlugin,
|
|
options.devServerPort ?? 4200
|
|
);
|
|
} else if (options.bundler === 'rspack') {
|
|
const { getRspackE2EWebServerInfo } = ensurePackage<
|
|
typeof import('@nx/rspack')
|
|
>('@nx/rspack', nxVersion);
|
|
e2eWebServerInfo = await getRspackE2EWebServerInfo(
|
|
tree,
|
|
options.projectName,
|
|
joinPathFragments(
|
|
options.appProjectRoot,
|
|
`rspack.config.${options.js ? 'js' : 'ts'}`
|
|
),
|
|
options.addPlugin,
|
|
options.devServerPort ?? 4200
|
|
);
|
|
} else if (options.bundler === 'vite') {
|
|
const { getViteE2EWebServerInfo, getReactRouterE2EWebServerInfo } =
|
|
ensurePackage<typeof import('@nx/vite')>('@nx/vite', nxVersion);
|
|
e2eWebServerInfo = options.useReactRouter
|
|
? await getReactRouterE2EWebServerInfo(
|
|
tree,
|
|
options.projectName,
|
|
joinPathFragments(
|
|
options.appProjectRoot,
|
|
`vite.config.${options.js ? 'js' : 'ts'}`
|
|
),
|
|
options.addPlugin,
|
|
options.devServerPort ?? 4200,
|
|
// If the user manually sets the port, then use it for dev and preview
|
|
options.port
|
|
)
|
|
: await getViteE2EWebServerInfo(
|
|
tree,
|
|
options.projectName,
|
|
joinPathFragments(
|
|
options.appProjectRoot,
|
|
`vite.config.${options.js ? 'js' : 'ts'}`
|
|
),
|
|
options.addPlugin,
|
|
options.devServerPort ?? 4200,
|
|
// If the user manually sets the port, then use it for dev and preview
|
|
options.port
|
|
);
|
|
} else if (options.bundler === 'rsbuild') {
|
|
ensurePackage('@nx/rsbuild', nxVersion);
|
|
const { getRsbuildE2EWebServerInfo } = await import(
|
|
'@nx/rsbuild/config-utils'
|
|
);
|
|
|
|
e2eWebServerInfo = await getRsbuildE2EWebServerInfo(
|
|
tree,
|
|
options.projectName,
|
|
joinPathFragments(
|
|
options.appProjectRoot,
|
|
`rsbuild.config.${options.js ? 'js' : 'ts'}`
|
|
),
|
|
options.addPlugin,
|
|
options.devServerPort ?? 4200
|
|
);
|
|
}
|
|
|
|
if (!hasNxBuildPlugin) {
|
|
await webStaticServeGenerator(tree, {
|
|
buildTarget: `${options.projectName}:build`,
|
|
targetName: 'serve-static',
|
|
spa: true,
|
|
});
|
|
}
|
|
switch (options.e2eTestRunner) {
|
|
case 'cypress': {
|
|
const { configurationGenerator } = ensurePackage<
|
|
typeof import('@nx/cypress')
|
|
>('@nx/cypress', nxVersion);
|
|
|
|
const packageJson: PackageJson = {
|
|
name: options.e2eProjectName,
|
|
version: '0.0.1',
|
|
private: true,
|
|
};
|
|
|
|
if (!options.useProjectJson) {
|
|
packageJson.nx = {
|
|
implicitDependencies: [options.projectName],
|
|
};
|
|
} else {
|
|
addProjectConfiguration(tree, options.e2eProjectName, {
|
|
projectType: 'application',
|
|
root: options.e2eProjectRoot,
|
|
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
|
targets: {},
|
|
implicitDependencies: [options.projectName],
|
|
tags: [],
|
|
});
|
|
}
|
|
|
|
if (!options.useProjectJson || options.isUsingTsSolutionConfig) {
|
|
writeJson(
|
|
tree,
|
|
joinPathFragments(options.e2eProjectRoot, 'package.json'),
|
|
packageJson
|
|
);
|
|
}
|
|
|
|
const e2eTask = await configurationGenerator(tree, {
|
|
...options,
|
|
project: options.e2eProjectName,
|
|
directory: 'src',
|
|
// the name and root are already normalized, instruct the generator to use them as is
|
|
bundler:
|
|
options.bundler === 'rspack'
|
|
? 'webpack'
|
|
: options.bundler === 'rsbuild'
|
|
? 'none'
|
|
: options.bundler,
|
|
skipFormat: true,
|
|
devServerTarget: e2eWebServerInfo.e2eDevServerTarget,
|
|
baseUrl: e2eWebServerInfo.e2eWebServerAddress,
|
|
jsx: true,
|
|
rootProject: options.rootProject,
|
|
webServerCommands: {
|
|
default: e2eWebServerInfo.e2eWebServerCommand,
|
|
production: e2eWebServerInfo.e2eCiWebServerCommand,
|
|
},
|
|
ciWebServerCommand: e2eWebServerInfo.e2eCiWebServerCommand,
|
|
ciBaseUrl: e2eWebServerInfo.e2eCiBaseUrl,
|
|
});
|
|
|
|
return e2eTask;
|
|
}
|
|
case 'playwright': {
|
|
const { configurationGenerator } = ensurePackage<
|
|
typeof import('@nx/playwright')
|
|
>('@nx/playwright', nxVersion);
|
|
|
|
const packageJson: PackageJson = {
|
|
name: options.e2eProjectName,
|
|
version: '0.0.1',
|
|
private: true,
|
|
};
|
|
|
|
if (!options.useProjectJson) {
|
|
packageJson.nx = {
|
|
implicitDependencies: [options.projectName],
|
|
};
|
|
} else {
|
|
addProjectConfiguration(tree, options.e2eProjectName, {
|
|
projectType: 'application',
|
|
root: options.e2eProjectRoot,
|
|
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
|
targets: {},
|
|
implicitDependencies: [options.projectName],
|
|
tags: [],
|
|
});
|
|
}
|
|
|
|
if (!options.useProjectJson || options.isUsingTsSolutionConfig) {
|
|
writeJson(
|
|
tree,
|
|
joinPathFragments(options.e2eProjectRoot, 'package.json'),
|
|
packageJson
|
|
);
|
|
}
|
|
|
|
const e2eTask = await configurationGenerator(tree, {
|
|
project: options.e2eProjectName,
|
|
skipFormat: true,
|
|
skipPackageJson: options.skipPackageJson,
|
|
directory: 'src',
|
|
js: false,
|
|
linter: options.linter,
|
|
setParserOptionsProject: options.setParserOptionsProject,
|
|
webServerCommand: e2eWebServerInfo.e2eCiWebServerCommand,
|
|
webServerAddress: e2eWebServerInfo.e2eCiBaseUrl,
|
|
rootProject: options.rootProject,
|
|
addPlugin: options.addPlugin,
|
|
});
|
|
|
|
return e2eTask;
|
|
}
|
|
case 'none':
|
|
default:
|
|
return () => {};
|
|
}
|
|
}
|