Colum Ferry 4b586a1acc
feat(rsbuild): add react and vue support for app generation (#29349)
## Current Behavior
We do not have a generator that can scaffold a react or vue app using
rsbuild.


## Expected Behavior
Update the react application generator to support a bundler option of
rsbuild
Update the vue application generator to support a bundler option of
rsbuild
2024-12-18 11:44:21 -05:00

205 lines
6.3 KiB
TypeScript

import type { GeneratorCallback, Tree } from '@nx/devkit';
import {
addProjectConfiguration,
ensurePackage,
joinPathFragments,
readNxJson,
} from '@nx/devkit';
import { webStaticServeGenerator } from '@nx/web';
import { nxVersion } from '../../../utils/versions';
import { NormalizedSchema } from '../schema';
import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file';
import { addE2eCiTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
import { E2EWebServerDetails } from '@nx/devkit/src/generators/e2e-web-server-info-utils';
export async function addE2e(
tree: Tree,
options: NormalizedSchema
): Promise<GeneratorCallback> {
const nxJson = readNxJson(tree);
const hasPlugin =
options.bundler === 'rsbuild'
? nxJson.plugins?.find((p) =>
typeof p === 'string'
? p === '@nx/rsbuild/plugin'
: p.plugin === '@nx/rsbuild/plugin'
)
: nxJson.plugins?.find((p) =>
typeof p === 'string'
? p === '@nx/vite/plugin'
: p.plugin === '@nx/vite/plugin'
);
let e2eWebServerInfo: E2EWebServerDetails;
if (options.bundler === 'vite') {
const { getViteE2EWebServerInfo } = ensurePackage<
typeof import('@nx/vite')
>('@nx/vite', nxVersion);
e2eWebServerInfo = await getViteE2EWebServerInfo(
tree,
options.projectName,
joinPathFragments(
options.appProjectRoot,
`vite.config.${options.js ? 'js' : 'ts'}`
),
options.addPlugin,
options.devServerPort ?? 4200
);
} 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
);
}
switch (options.e2eTestRunner) {
case 'cypress': {
if (!hasPlugin) {
await webStaticServeGenerator(tree, {
buildTarget: `${options.projectName}:build`,
targetName: 'serve-static',
spa: true,
});
}
const { configurationGenerator } = ensurePackage<
typeof import('@nx/cypress')
>('@nx/cypress', nxVersion);
addProjectConfiguration(tree, options.e2eProjectName, {
projectType: 'application',
root: options.e2eProjectRoot,
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
targets: {},
tags: [],
implicitDependencies: [options.projectName],
});
const e2eTask = await configurationGenerator(tree, {
...options,
project: options.e2eProjectName,
directory: 'src',
bundler: 'vite',
skipFormat: true,
devServerTarget: e2eWebServerInfo.e2eDevServerTarget,
baseUrl: e2eWebServerInfo.e2eWebServerAddress,
jsx: true,
webServerCommands: hasPlugin
? {
default: e2eWebServerInfo.e2eWebServerCommand,
production: e2eWebServerInfo.e2eCiWebServerCommand,
}
: undefined,
ciWebServerCommand: e2eWebServerInfo.e2eCiWebServerCommand,
ciBaseUrl: e2eWebServerInfo.e2eCiBaseUrl,
});
if (
options.addPlugin ||
readNxJson(tree).plugins?.find((p) =>
typeof p === 'string'
? p === '@nx/cypress/plugin'
: p.plugin === '@nx/cypress/plugin'
)
) {
let buildTarget = '^build';
if (hasPlugin) {
const matchingPlugin = await findPluginForConfigFile(
tree,
`@nx/vite/plugin`,
joinPathFragments(
options.appProjectRoot,
`vite.config.${options.js ? 'js' : 'ts'}`
)
);
if (matchingPlugin && typeof matchingPlugin !== 'string') {
buildTarget = `^${
(matchingPlugin.options as any)?.buildTargetName ?? 'build'
}`;
}
}
await addE2eCiTargetDefaults(
tree,
'@nx/cypress/plugin',
buildTarget,
joinPathFragments(
options.e2eProjectRoot,
`cypress.config.${options.js ? 'js' : 'ts'}`
)
);
}
return e2eTask;
}
case 'playwright': {
const { configurationGenerator } = ensurePackage<
typeof import('@nx/playwright')
>('@nx/playwright', nxVersion);
addProjectConfiguration(tree, options.e2eProjectName, {
projectType: 'application',
root: options.e2eProjectRoot,
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
targets: {},
implicitDependencies: [options.projectName],
});
const e2eTask = await configurationGenerator(tree, {
...options,
project: options.e2eProjectName,
skipFormat: true,
skipPackageJson: options.skipPackageJson,
directory: 'src',
js: false,
linter: options.linter,
setParserOptionsProject: options.setParserOptionsProject,
webServerCommand: e2eWebServerInfo.e2eCiWebServerCommand,
webServerAddress: e2eWebServerInfo.e2eCiBaseUrl,
});
if (
options.addPlugin ||
readNxJson(tree).plugins?.find((p) =>
typeof p === 'string'
? p === '@nx/playwright/plugin'
: p.plugin === '@nx/playwright/plugin'
)
) {
let buildTarget = '^build';
if (hasPlugin) {
const matchingPlugin = await findPluginForConfigFile(
tree,
`@nx/vite/plugin`,
joinPathFragments(
options.appProjectRoot,
`vite.config.${options.js ? 'js' : 'ts'}`
)
);
if (matchingPlugin && typeof matchingPlugin !== 'string') {
buildTarget = `^${
(matchingPlugin.options as any)?.buildTargetName ?? 'build'
}`;
}
}
await addE2eCiTargetDefaults(
tree,
'@nx/playwright/plugin',
buildTarget,
joinPathFragments(options.e2eProjectRoot, `playwright.config.ts`)
);
}
return e2eTask;
}
case 'none':
default:
return () => {};
}
}