nx/packages/create-nx-workspace/src/create-workspace.ts
Nicholas Cunningham 363088a8ae
feat(react): Add react-router to create-nx-workspace and react app generator (#30316)
This pull request introduces improvements to React Router integration
and removes the Remix preset.

## Key Changes:
- Updated `create-nx-workspace` to support React Router.
- Removed the Remix option from `create-nx-workspace`, but the package
remains to support existing users.

## SSR & React Router Support
- New users who want SSR in their React apps can enable it via the React
option and select React Router for SSR support.
- The ecosystem has shifted to migrating from Remix to React Router for
SSR needs.
- This option is only available for plain React apps and uses Vite.
Other types of React apps (Micro Frontends, Webpack, Rspack, etc.)
remain unaffected.

## Default Routing Behavior
`--routing` is now enabled by default when creating a React app using
`create-nx-workspace`, aligning with Angular’s default behaviour.
2025-03-14 15:06:54 -04:00

122 lines
3.4 KiB
TypeScript

import { CreateWorkspaceOptions } from './create-workspace-options';
import { output } from './utils/output';
import { getOnboardingInfo, readNxCloudToken } from './utils/nx/nx-cloud';
import { createSandbox } from './create-sandbox';
import { createEmptyWorkspace } from './create-empty-workspace';
import { createPreset } from './create-preset';
import { setupCI } from './utils/ci/setup-ci';
import { initializeGitRepo } from './utils/git/git';
import { getPackageNameFromThirdPartyPreset } from './utils/preset/get-third-party-preset';
import { mapErrorToBodyLines } from './utils/error-utils';
import { Preset } from './utils/preset/preset';
export async function createWorkspace<T extends CreateWorkspaceOptions>(
preset: string,
options: T
) {
const {
packageManager,
name,
nxCloud,
skipGit = false,
defaultBase = 'main',
commit,
cliName,
useGitHub,
} = options;
if (cliName) {
output.setCliName(cliName ?? 'NX');
}
const tmpDir = await createSandbox(packageManager);
const workspaceGlobs = getWorkspaceGlobsFromPreset(preset);
// nx new requires a preset currently. We should probably make it optional.
const directory = await createEmptyWorkspace<T>(
tmpDir,
name,
packageManager,
{ ...options, preset, workspaceGlobs }
);
// If the preset is a third-party preset, we need to call createPreset to install it
// For first-party presets, it will be created by createEmptyWorkspace instead.
// In createEmptyWorkspace, it will call `nx new` -> `@nx/workspace newGenerator` -> `@nx/workspace generatePreset`.
const thirdPartyPackageName = getPackageNameFromThirdPartyPreset(preset);
if (thirdPartyPackageName) {
await createPreset(
thirdPartyPackageName,
options,
packageManager,
directory
);
}
let connectUrl: string | undefined;
let nxCloudInfo: string | undefined;
if (nxCloud !== 'skip') {
const token = readNxCloudToken(directory) as string;
if (nxCloud !== 'yes') {
await setupCI(directory, nxCloud, packageManager);
}
const { connectCloudUrl, output } = await getOnboardingInfo(
nxCloud,
token,
directory,
useGitHub
);
connectUrl = connectCloudUrl;
nxCloudInfo = output;
}
if (!skipGit) {
try {
await initializeGitRepo(directory, { defaultBase, commit, connectUrl });
} catch (e) {
if (e instanceof Error) {
output.error({
title: 'Could not initialize git repository',
bodyLines: mapErrorToBodyLines(e),
});
} else {
console.error(e);
}
}
}
return {
nxCloudInfo,
directory,
};
}
export function extractConnectUrl(text: string): string | null {
const urlPattern = /(https:\/\/[^\s]+\/connect\/[^\s]+)/g;
const match = text.match(urlPattern);
return match ? match[0] : null;
}
function getWorkspaceGlobsFromPreset(preset: string): string[] {
// Should match how apps are created in `packages/workspace/src/generators/preset/preset.ts`.
switch (preset) {
case Preset.AngularMonorepo:
case Preset.Expo:
case Preset.Express:
case Preset.Nest:
case Preset.NextJs:
case Preset.NodeMonorepo:
case Preset.Nuxt:
case Preset.ReactNative:
case Preset.ReactMonorepo:
case Preset.VueMonorepo:
case Preset.WebComponents:
return ['apps/*'];
default:
return ['packages/*'];
}
}