Jack Hsu 55251ca0bf
fix(react): do not set styles.tailwind for executor options for projects not using inferred targets (#31667)
This PR fixes an issue when you use React with Webpack/Rspack, and
aren't using `@nx/webpack/plugin` or `@nx/rspack/plugin`.



<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
Project configuration contains this for build options:

```
"styles": ["src/myapp/styles.tailwind"]
```

## Expected Behavior


It shoud be :

```
"styles": ["src/myapp/styles.css"]
```

Which is what we actually generate.
2025-06-20 15:02:27 -04:00

265 lines
7.2 KiB
TypeScript

import { NormalizedSchema } from '../schema';
import {
addProjectConfiguration,
joinPathFragments,
ProjectConfiguration,
TargetConfiguration,
Tree,
updateJson,
writeJson,
} from '@nx/devkit';
import { hasWebpackPlugin } from '../../../utils/has-webpack-plugin';
import { maybeJs } from '../../../utils/maybe-js';
import { hasRspackPlugin } from '../../../utils/has-rspack-plugin';
import type { PackageJson } from 'nx/src/utils/package-json';
export function addProject(host: Tree, options: NormalizedSchema) {
const project: ProjectConfiguration = {
root: options.appProjectRoot,
sourceRoot: `${options.appProjectRoot}/src`,
projectType: 'application',
targets: {},
tags: options.parsedTags,
};
if (options.bundler === 'webpack') {
if (!hasWebpackPlugin(host) || !options.addPlugin) {
project.targets = {
build: createBuildTarget(options),
serve: createServeTarget(options),
};
}
} else if (
options.bundler === 'rspack' &&
(!hasRspackPlugin(host) || !options.addPlugin)
) {
project.targets = {
build: createRspackBuildTarget(options),
serve: createRspackServeTarget(options),
};
}
const packageJson: PackageJson = {
name: options.importPath,
version: '0.0.1',
private: true,
};
if (!options.useProjectJson) {
if (options.projectName !== options.importPath) {
packageJson.nx = { name: options.projectName };
}
if (Object.keys(project.targets).length) {
packageJson.nx ??= {};
packageJson.nx.targets = project.targets;
}
if (options.parsedTags?.length) {
packageJson.nx ??= {};
packageJson.nx.tags = options.parsedTags;
}
} else {
addProjectConfiguration(host, options.projectName, {
...project,
});
}
if (!options.useProjectJson || options.isUsingTsSolutionConfig) {
// React Router already adds a package.json to the project root
if (options.useReactRouter) {
updateJson(
host,
joinPathFragments(options.appProjectRoot, 'package.json'),
(json) => {
return {
name: packageJson.name,
...json,
};
}
);
} else {
writeJson(
host,
joinPathFragments(options.appProjectRoot, 'package.json'),
packageJson
);
}
}
}
function createRspackBuildTarget(
options: NormalizedSchema
): TargetConfiguration {
return {
executor: '@nx/rspack:rspack',
outputs: ['{options.outputPath}'],
defaultConfiguration: 'production',
options: {
outputPath: options.isUsingTsSolutionConfig
? joinPathFragments(options.appProjectRoot, 'dist')
: joinPathFragments(
'dist',
options.appProjectRoot !== '.'
? options.appProjectRoot
: options.projectName
),
index: joinPathFragments(options.appProjectRoot, 'src/index.html'),
baseHref: '/',
main: joinPathFragments(
options.appProjectRoot,
maybeJs(options, `src/main.tsx`)
),
tsConfig: joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
assets: [
joinPathFragments(options.appProjectRoot, 'src/favicon.ico'),
joinPathFragments(options.appProjectRoot, 'src/assets'),
],
rspackConfig: joinPathFragments(
options.appProjectRoot,
'rspack.config.js'
),
styles:
options.styledModule || !options.hasStyles
? []
: [
joinPathFragments(
options.appProjectRoot,
`src/styles.${
options.style === 'tailwind' ? 'css' : options.style
}`
),
],
scripts: [],
configurations: {
development: {
mode: 'development',
},
production: {
mode: 'production',
optimization: true,
sourceMap: false,
outputHashing: 'all',
namedChunks: false,
extractLicenses: true,
vendorChunk: false,
},
},
},
};
}
function createRspackServeTarget(
options: NormalizedSchema
): TargetConfiguration {
return {
executor: '@nx/rspack:dev-server',
defaultConfiguration: 'development',
options: {
buildTarget: `${options.projectName}:build`,
hmr: true,
},
configurations: {
development: {
buildTarget: `${options.projectName}:build:development`,
},
production: {
buildTarget: `${options.projectName}:build:production`,
hmr: false,
},
},
};
}
function createBuildTarget(options: NormalizedSchema): TargetConfiguration {
return {
executor: '@nx/webpack:webpack',
outputs: ['{options.outputPath}'],
defaultConfiguration: 'production',
options: {
compiler: options.compiler ?? 'babel',
outputPath: options.isUsingTsSolutionConfig
? joinPathFragments(options.appProjectRoot, 'dist')
: joinPathFragments(
'dist',
options.appProjectRoot !== '.'
? options.appProjectRoot
: options.projectName
),
index: joinPathFragments(options.appProjectRoot, 'src/index.html'),
baseHref: '/',
main: joinPathFragments(
options.appProjectRoot,
maybeJs(options, `src/main.tsx`)
),
tsConfig: joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
assets: [
joinPathFragments(options.appProjectRoot, 'src/favicon.ico'),
joinPathFragments(options.appProjectRoot, 'src/assets'),
],
styles:
options.styledModule || !options.hasStyles
? []
: [
joinPathFragments(
options.appProjectRoot,
`src/styles.${
options.style === 'tailwind' ? 'css' : options.style
}`
),
],
scripts: [],
webpackConfig: joinPathFragments(
options.appProjectRoot,
'webpack.config.js'
),
},
configurations: {
development: {
extractLicenses: false,
optimization: false,
sourceMap: true,
vendorChunk: true,
},
production: {
fileReplacements: [
{
replace: joinPathFragments(
options.appProjectRoot,
maybeJs(options, `src/environments/environment.ts`)
),
with: joinPathFragments(
options.appProjectRoot,
maybeJs(options, `src/environments/environment.prod.ts`)
),
},
],
optimization: true,
outputHashing: 'all',
sourceMap: false,
namedChunks: false,
extractLicenses: true,
vendorChunk: false,
},
},
};
}
function createServeTarget(options: NormalizedSchema): TargetConfiguration {
return {
executor: '@nx/webpack:dev-server',
defaultConfiguration: 'development',
options: {
buildTarget: `${options.projectName}:build`,
hmr: true,
},
configurations: {
development: {
buildTarget: `${options.projectName}:build:development`,
},
production: {
buildTarget: `${options.projectName}:build:production`,
hmr: false,
},
},
};
}