fix(rspack): ensure nest applications generated correctly #31204 (#31424)

- fix(rspack): choosing nest as framework should not result in error
#31204
- fix(rspack): add deprecation message for application generator
- fix(rspack): ensure application generated projects are added to
excludes

## Current Behavior
Running the `@nx/rspack:application` generator with `--framework=nest`
results in an error due to mix of inferred and executor usage throughout
the generation process.

## Expected Behavior
Running the generator should pass without failure and create a working
project.
Deprecate the generator in favour of using project specific packages
(@nx/react etc)

## Related Issue(s)

Fixes #31204

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: Coly010 <Coly010@users.noreply.github.com>
This commit is contained in:
Colum Ferry 2025-06-03 14:41:17 +01:00 committed by GitHub
parent d3faf53c56
commit 34cf5a243f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 122 additions and 23 deletions

View File

@ -7,6 +7,7 @@
"title": "Application generator for React + rspack",
"type": "object",
"description": "React + Rspack application generator.",
"x-deprecated": "This generator will be removed in Nx 22. Please use the equivalent generator for your application type instead.",
"examples": [
{
"command": "nx g app myorg/myapp",
@ -90,6 +91,7 @@
"aliases": ["app"],
"x-type": "application",
"description": "React application generator.",
"x-deprecated": "This generator will be removed in Nx 22. Please use the equivalent generator for your application type instead.",
"implementation": "/packages/rspack/src/generators/application/application.ts",
"hidden": false,
"path": "/packages/rspack/src/generators/application/schema.json",

View File

@ -197,7 +197,9 @@ describe('app', () => {
"targets": {
"build": {
"configurations": {
"development": {},
"development": {
"outputHashing": "none",
},
"production": {},
},
"defaultConfiguration": "production",
@ -366,7 +368,9 @@ describe('app', () => {
"targets": {
"build": {
"configurations": {
"development": {},
"development": {
"outputHashing": "none",
},
"production": {},
},
"defaultConfiguration": "production",

View File

@ -31,7 +31,9 @@ describe('node app generator (legacy)', () => {
expect(project.targets.build).toMatchInlineSnapshot(`
{
"configurations": {
"development": {},
"development": {
"outputHashing": "none",
},
"production": {},
},
"defaultConfiguration": "production",

View File

@ -95,7 +95,9 @@ function getWebpackBuildConfig(
generatePackageJson: options.isUsingTsSolutionConfig ? undefined : true,
},
configurations: {
development: {},
development: {
outputHashing: 'none',
},
production: {
...(options.docker && { generateLockfile: true }),
},
@ -197,7 +199,7 @@ function addProject(tree: Tree, options: NormalizedSchema) {
addBuildTargetDefaults(tree, '@nx/esbuild:esbuild');
project.targets.build = getEsBuildConfig(project, options);
} else if (options.bundler === 'webpack') {
if (!hasWebpackPlugin(tree)) {
if (!hasWebpackPlugin(tree) && options.addPlugin === false) {
addBuildTargetDefaults(tree, `@nx/webpack:webpack`);
project.targets.build = getWebpackBuildConfig(project, options);
} else if (options.isNest) {
@ -253,7 +255,8 @@ function addAppFiles(tree: Tree, options: NormalizedSchema) {
tree,
options.appProjectRoot
),
webpackPluginOptions: hasWebpackPlugin(tree)
webpackPluginOptions:
hasWebpackPlugin(tree) && options.addPlugin !== false
? {
outputPath: options.isUsingTsSolutionConfig
? 'dist'

View File

@ -25,7 +25,8 @@
"schema": "./src/generators/application/schema.json",
"aliases": ["app"],
"x-type": "application",
"description": "React application generator."
"description": "React application generator.",
"x-deprecated": "This generator will be removed in Nx 22. Please use the equivalent generator for your application type instead."
},
"convert-webpack": {
"alias": "convert-to-rspack",

View File

@ -1,14 +1,82 @@
import { ensurePackage, formatFiles, runTasksInSerial, Tree } from '@nx/devkit';
import {
ensurePackage,
formatFiles,
logger,
readNxJson,
runTasksInSerial,
Tree,
updateNxJson,
} from '@nx/devkit';
import { version as nxVersion } from 'nx/package.json';
import configurationGenerator from '../configuration/configuration';
import rspackInitGenerator from '../init/init';
import { normalizeOptions } from './lib/normalize-options';
import { ApplicationGeneratorSchema } from './schema';
import { ApplicationGeneratorSchema, NormalizedSchema } from './schema';
/**
* Updates the exclude field for any @nx/rspack/plugin registrations in nx.json
*/
function updateRspackPluginExclusion(tree: Tree, options: NormalizedSchema) {
const nxJson = readNxJson(tree);
if (!nxJson.plugins?.length) {
return;
}
let updated = false;
// Loop through all plugins to find @nx/rspack/plugin registrations
for (let i = 0; i < nxJson.plugins.length; i++) {
const plugin = nxJson.plugins[i];
const isRspackPlugin =
typeof plugin === 'string'
? plugin === '@nx/rspack/plugin'
: plugin.plugin === '@nx/rspack/plugin';
if (!isRspackPlugin) {
continue;
}
if (typeof plugin === 'string') {
// Convert string notation to object notation with exclude field
nxJson.plugins[i] = {
plugin: '@nx/rspack/plugin',
exclude: [`${options.appProjectRoot}/**`],
};
updated = true;
} else {
// Object notation
if (!plugin.exclude) {
// Add exclude field if it doesn't exist
plugin.exclude = [`${options.appProjectRoot}/**`];
updated = true;
} else if (Array.isArray(plugin.exclude)) {
// Add to existing exclude field if it's an array
plugin.exclude.push(`${options.appProjectRoot}/**`);
updated = true;
}
}
}
if (updated) {
updateNxJson(tree, nxJson);
}
}
// TODO(v22) - remove this generator
export default async function (
tree: Tree,
_options: ApplicationGeneratorSchema
) {
// Add deprecation warning with alternatives based on framework
const framework = _options.framework || 'react'; // Default is react
logger.warn(
`The @nx/rspack:application generator is deprecated and will be removed in Nx 22. ` +
`Please use @nx/${
framework === 'nest' ? 'nest' : framework === 'web' ? 'web' : 'react'
}:application instead.`
);
const tasks = [];
const initTask = await rspackInitGenerator(tree, {
..._options,
@ -17,6 +85,10 @@ export default async function (
const options = await normalizeOptions(tree, _options);
if (framework === 'nest') {
updateRspackPluginExclusion(tree, options);
}
options.style ??= 'css';
if (options.framework === 'nest') {
@ -37,6 +109,7 @@ export default async function (
newProject: false,
buildTarget: 'build',
framework: 'nest',
addPlugin: false,
});
tasks.push(createAppTask, convertAppTask);
@ -92,6 +165,7 @@ export default async function (
buildTarget: 'build',
serveTarget: 'serve',
framework: 'react',
addPlugin: false,
});
tasks.push(createAppTask, convertAppTask);
}

View File

@ -4,6 +4,7 @@
"title": "Application generator for React + rspack",
"type": "object",
"description": "React + Rspack application generator.",
"x-deprecated": "This generator will be removed in Nx 22. Please use the equivalent generator for your application type instead.",
"examples": [
{
"command": "nx g app myorg/myapp",

View File

@ -190,6 +190,16 @@ export function addOrChangeBuildTarget(
assets,
};
const existingProjectConfigurations = {};
const buildTarget = project.targets.build;
if (buildTarget && buildTarget.configurations) {
for (const [configurationName, configuration] of Object.entries(
buildTarget.configurations
)) {
existingProjectConfigurations[configurationName] = configuration;
}
}
project.targets ??= {};
project.targets[target] = {
@ -199,9 +209,11 @@ export function addOrChangeBuildTarget(
options: buildOptions,
configurations: {
development: {
...(existingProjectConfigurations['development'] ?? {}),
mode: 'development',
},
production: {
...(existingProjectConfigurations['production'] ?? {}),
mode: 'production',
optimization: options.target === 'web' ? true : undefined,
sourceMap: false,
@ -371,7 +383,7 @@ function generateNestConfig(
project: ProjectConfiguration,
buildOptions: RspackExecutorSchema
): string {
if (hasPlugin(tree)) {
if (hasPlugin(tree) && options.addPlugin !== false) {
return `
const { NxAppRspackPlugin } = require('@nx/rspack/app-plugin');
const rspack = require('@rspack/core');