Jack Hsu ec5a5e6360
feat(react): update app and lib generators to support new TS solution setup (#28808)
This PR updates app and lib generators in the following packages such
that they will generate files with the TS solution setup if it is
detected.

- `@nx/react`
- `@nx/next`
- `@nx/remix`
- `@nx/expo`
- `@nx/react-native`

React apps and libs will be linked using npm/pnpm/yarn/bun workspaces
feature rather than through tsconfig paths. This means that local
aliases like `@/` will work with Next.js and Remix apps.

Note: This will be behind `--workspaces` flag when using `npx
create-nx-workspace` and choosing React stack. If you use the None/TS
stack then adding plugins like `nx add @nx/react` then generating apps,
it will automatically pick up the new TS solution setup.


<!-- 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
React generators are not compatible with TS solution setup (i.e.
workspaces + TS project references).

## Expected Behavior
React generators work with new TS solution setup (Plain, Next.js, Remix,
Expo, React Native).

## Related Issue(s)
#28322

---------

Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
Co-authored-by: Nicholas Cunningham <ndcunningham@gmail.com>
2024-11-28 22:18:45 -05:00

98 lines
2.7 KiB
TypeScript

import { NormalizedSchema } from './normalize-options';
import {
addProjectConfiguration,
joinPathFragments,
ProjectConfiguration,
readNxJson,
Tree,
writeJson,
} from '@nx/devkit';
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
import { getImportPath } from '@nx/js/src/utils/get-import-path';
import { nextVersion } from '../../../utils/versions';
import { reactDomVersion, reactVersion } from '@nx/react';
export function addProject(host: Tree, options: NormalizedSchema) {
const targets: Record<string, any> = {};
// Check if plugin exists in nx.json and if it doesn't then we can continue
// with the default targets.
const nxJson = readNxJson(host);
const hasPlugin = nxJson.plugins?.some((p) =>
typeof p === 'string'
? p === '@nx/next/plugin'
: p.plugin === '@nx/next/plugin'
);
if (!hasPlugin) {
addBuildTargetDefaults(host, '@nx/next:build');
targets.build = {
executor: '@nx/next:build',
outputs: ['{options.outputPath}'],
defaultConfiguration: 'production',
options: {
outputPath: options.outputPath,
},
configurations: {
development: {
outputPath: options.appProjectRoot,
},
production: {},
},
};
targets.serve = {
executor: '@nx/next:server',
defaultConfiguration: 'development',
options: {
buildTarget: `${options.projectName}:build`,
dev: true,
},
configurations: {
development: {
buildTarget: `${options.projectName}:build:development`,
dev: true,
},
production: {
buildTarget: `${options.projectName}:build:production`,
dev: false,
},
},
};
}
const project: ProjectConfiguration = {
root: options.appProjectRoot,
sourceRoot: options.appProjectRoot,
projectType: 'application',
targets,
tags: options.parsedTags,
};
if (isUsingTsSolutionSetup(host)) {
writeJson(host, joinPathFragments(options.appProjectRoot, 'package.json'), {
name: getImportPath(host, options.name),
version: '0.0.1',
private: true,
dependencies: {
next: nextVersion,
react: reactVersion,
'react-dom': reactDomVersion,
},
nx: {
name: options.name,
projectType: 'application',
sourceRoot: options.appProjectRoot,
tags: options.parsedTags?.length ? options.parsedTags : undefined,
},
});
} else {
addProjectConfiguration(host, options.projectName, {
...project,
});
}
}