From 664eefc0f6eec7609c537e77f2b40715ebe8562e Mon Sep 17 00:00:00 2001 From: Nicholas Cunningham Date: Wed, 4 Dec 2024 11:11:36 -0700 Subject: [PATCH] fix(core): React workspaces that use pnpm & the new TS solution should be declared correctly so that it can be referenced. --- e2e/react/react-npm-ts-solution.test.ts | 59 ++++++++++++++++++ e2e/react/src/react-pnpm-ts-solution.test.ts | 62 +++++++++++++++++++ e2e/react/src/react.test.ts | 25 +------- e2e/utils/create-project-utils.ts | 16 ++++- .../src/generators/application/application.ts | 7 +++ .../expo/src/generators/library/library.ts | 5 ++ .../src/generators/application/application.ts | 7 +++ .../library/lib/normalize-options.ts | 3 + .../next/src/generators/library/library.ts | 5 ++ .../src/generators/application/application.ts | 7 +++ .../src/generators/library/library.ts | 5 ++ packages/react/package.json | 3 +- .../src/generators/application/application.ts | 15 ++++- .../library/lib/normalize-options.ts | 1 - .../react/src/generators/library/library.ts | 4 ++ .../src/utils/add-app-to-pnpm-workspace.ts | 33 ++++++++++ .../application/application.impl.ts | 7 +++ .../library/lib/normalize-options.ts | 3 + .../src/generators/library/library.impl.ts | 5 ++ .../new/generate-workspace-files.spec.ts | 4 +- .../new/generate-workspace-files.ts | 2 +- 21 files changed, 246 insertions(+), 32 deletions(-) create mode 100644 e2e/react/react-npm-ts-solution.test.ts create mode 100644 e2e/react/src/react-pnpm-ts-solution.test.ts create mode 100644 packages/react/src/utils/add-app-to-pnpm-workspace.ts diff --git a/e2e/react/react-npm-ts-solution.test.ts b/e2e/react/react-npm-ts-solution.test.ts new file mode 100644 index 00000000000000..5ded23b9c43c70 --- /dev/null +++ b/e2e/react/react-npm-ts-solution.test.ts @@ -0,0 +1,59 @@ +const { load } = require('@zkochan/js-yaml'); +import { + cleanupProject, + runCLI, + newProject, + ensureCypressInstallation, + uniq, + readJson, +} from '@nx/e2e/utils'; + +describe('React typescript project references PM = npm', () => { + beforeEach(() => { + cleanupProject(); + newProject({ + packages: ['@nx/react'], + packageManager: 'npm', + workspaces: true, + }); + ensureCypressInstallation(); + }); + + afterEach(() => cleanupProject()); + it('None buildable libs using should be excluded from js/ts plugin', async () => { + const appName = uniq('app'); + const libName = uniq('lib'); + + runCLI( + `generate @nx/react:app apps/${appName} --name=${appName} --useTsSolution=true --bundler=vite --no-interactive --skipFormat --linter=eslint --unitTestRunner=vitest` + ); + runCLI( + `generate @nx/react:lib ${libName} --bundler=none --no-interactive --unit-test-runner=vitest --skipFormat --linter=eslint` + ); + + const nxJson = readJson('nx.json'); + + const jsTypescriptPlugin = nxJson.plugins.find( + (plugin) => plugin.plugin === '@nx/js/typescript' + ); + expect(jsTypescriptPlugin).toBeDefined(); + + expect(jsTypescriptPlugin.exclude.includes(`${libName}/*`)).toBeTruthy(); + }, 250_000); + + it('Apps/libs using should be added to workspaces', async () => { + const appName = uniq('app'); + const libName = uniq('lib'); + + runCLI( + `generate @nx/react:app apps/${appName} --name=${appName} --useTsSolution=true --bundler=vite --no-interactive --skipFormat --linter=eslint --unitTestRunner=vitest` + ); + runCLI( + `generate @nx/react:lib ${libName} --bundler=vite --no-interactive --unit-test-runner=vitest --skipFormat --linter=eslint` + ); + + const packageJson = readJson('package.json'); + expect(packageJson.workspaces).toContain(`apps/${appName}`); + expect(packageJson.workspaces).toContain(`${libName}/*`); + }); +}); diff --git a/e2e/react/src/react-pnpm-ts-solution.test.ts b/e2e/react/src/react-pnpm-ts-solution.test.ts new file mode 100644 index 00000000000000..51f92b7ec793cb --- /dev/null +++ b/e2e/react/src/react-pnpm-ts-solution.test.ts @@ -0,0 +1,62 @@ +const { load } = require('@zkochan/js-yaml'); +import { + cleanupProject, + runCLI, + newProject, + ensureCypressInstallation, + uniq, + readFile, + readJson, +} from '@nx/e2e/utils'; + +describe('React typescript project references PM = pnpm', () => { + beforeAll(() => { + newProject({ + packages: ['@nx/react'], + packageManager: 'pnpm', + workspaces: true, + }); + + ensureCypressInstallation(); + }); + + afterAll(() => cleanupProject()); + + it('None buildable libs using should be excluded from js/ts plugin', async () => { + const appName = uniq('app'); + const libName = uniq('lib'); + + runCLI( + `generate @nx/react:app apps/${appName} --name=${appName} --useTsSolution=true --bundler=vite --no-interactive --skipFormat --linter=eslint --unitTestRunner=vitest` + ); + runCLI( + `generate @nx/react:lib ${libName} --bundler=none --no-interactive --unit-test-runner=vitest --skipFormat --linter=eslint` + ); + + const nxJson = readJson('nx.json'); + + const jsTypescriptPlugin = nxJson.plugins.find( + (plugin) => plugin.plugin === '@nx/js/typescript' + ); + expect(jsTypescriptPlugin).toBeDefined(); + + expect(jsTypescriptPlugin.exclude.includes(`${libName}/*`)).toBeTruthy(); + }, 250_000); + + it('PNPM Apps/libs using should be added to workspaces', async () => { + const appName = uniq('app'); + const libName = uniq('lib'); + + runCLI( + `generate @nx/react:app apps/${appName} --name=${appName} --useTsSolution=true --bundler=vite --no-interactive --skipFormat --linter=eslint --unitTestRunner=vitest` + ); + runCLI( + `generate @nx/react:lib ${libName} --bundler=vite --no-interactive --unit-test-runner=vitest --skipFormat --linter=eslint` + ); + + const pnpmWorkspaceContent = readFile('pnpm-workspace.yaml'); + const pnmpWorkspaceYaml = load(pnpmWorkspaceContent); + expect(pnmpWorkspaceYaml.packages).toContain(`apps/${appName}`); + expect(pnmpWorkspaceYaml.packages).toContain(`${libName}/*`); + }); +}); diff --git a/e2e/react/src/react.test.ts b/e2e/react/src/react.test.ts index 8e5db024e982ea..720ce4a09dc14d 100644 --- a/e2e/react/src/react.test.ts +++ b/e2e/react/src/react.test.ts @@ -20,7 +20,6 @@ import { join } from 'path'; describe('React Applications', () => { let proj: string; - describe('Crystal Supported Tests', () => { beforeAll(() => { proj = newProject({ packages: ['@nx/react'] }); @@ -28,13 +27,12 @@ describe('React Applications', () => { }); afterAll(() => cleanupProject()); - it('should be able to use Vite to build and test apps', async () => { const appName = uniq('app'); const libName = uniq('lib'); runCLI( - `generate @nx/react:app apps/${appName} --name=${appName} --bundler=vite --no-interactive --skipFormat --linter=eslint --unitTestRunner=vitest` + `generate @nx/react:app apps/${appName} --name=${appName} --bundler=vite --no-interactive --skipFormat --linter=eslint --unitTestRunner=vitest` ); runCLI( `generate @nx/react:lib libs/${libName} --bundler=none --no-interactive --unit-test-runner=vitest --skipFormat --linter=eslint` @@ -63,27 +61,6 @@ describe('React Applications', () => { } }, 250_000); - it('None buildable libs using (useTsSolution = true) should be excluded from js/ts plugin', async () => { - const appName = uniq('app'); - const libName = uniq('lib'); - - runCLI( - `generate @nx/react:app apps/${appName} --name=${appName} --useTsSolution true --bundler=vite --no-interactive --skipFormat --linter=eslint --unitTestRunner=vitest` - ); - runCLI( - `generate @nx/react:lib ${libName} --bundler=none --no-interactive --unit-test-runner=vitest --skipFormat --linter=eslint` - ); - - const nxJson = JSON.parse(readFile('nx.json')); - - const jsTypescriptPlugin = nxJson.plugins.find( - (plugin) => plugin.plugin === '@nx/js/typescript' - ); - expect(jsTypescriptPlugin).toBeDefined(); - - expect(jsTypescriptPlugin.exclude.includes(`${libName}/*`)).toBeTruthy(); - }, 250_000); - it('should be able to use Rspack to build and test apps', async () => { const appName = uniq('app'); const libName = uniq('lib'); diff --git a/e2e/utils/create-project-utils.ts b/e2e/utils/create-project-utils.ts index 7199e95e8623c0..745f9785944f58 100644 --- a/e2e/utils/create-project-utils.ts +++ b/e2e/utils/create-project-utils.ts @@ -76,10 +76,12 @@ export function newProject({ name = uniq('proj'), packageManager = getSelectedPackageManager(), packages, + workspaces = false, // Add this temporary flag to enable ts workspaces in the new project }: { name?: string; packageManager?: 'npm' | 'yarn' | 'pnpm' | 'bun'; readonly packages?: Array; + workspaces?: boolean; } = {}): string { const newProjectStart = performance.mark('new-project:start'); try { @@ -95,6 +97,7 @@ export function newProject({ runCreateWorkspace(projScope, { preset: 'apps', packageManager, + workspaces, }); const createNxWorkspaceEnd = performance.mark('create-nx-workspace:end'); createNxWorkspaceMeasure = performance.measure( @@ -228,6 +231,7 @@ export function runCreateWorkspace( ssr, framework, prefix, + workspaces, }: { preset: string; appName?: string; @@ -249,13 +253,17 @@ export function runCreateWorkspace( ssr?: boolean; framework?: string; prefix?: string; + workspaces?: boolean; } ) { projName = name; const pm = getPackageManagerCommand({ packageManager }); + preset = workspaces ? 'ts' : preset; + let command = `${pm.createWorkspace} ${name} --preset=${preset} --nxCloud=skip --no-interactive`; + if (appName) { command += ` --appName=${appName}`; } @@ -327,6 +335,10 @@ export function runCreateWorkspace( command += ` --prefix=${prefix}`; } + if (workspaces) { + command += ` --workspaces=true`; + } + try { const create = execSync(`${command}${isVerbose() ? ' --verbose' : ''}`, { cwd, @@ -674,7 +686,9 @@ export function cleanupProject({ } catch {} // ignore crashed daemon try { removeSync(tmpProjPath()); - } catch {} + } catch { + console.error(`Failed to remove ${tmpProjPath()}`); + } } resetWorkspaceContext(); } diff --git a/packages/expo/src/generators/application/application.ts b/packages/expo/src/generators/application/application.ts index 4c971cbc324b12..0ffa3ddab09cfa 100644 --- a/packages/expo/src/generators/application/application.ts +++ b/packages/expo/src/generators/application/application.ts @@ -21,6 +21,7 @@ import { Schema } from './schema'; import { ensureDependencies } from '../../utils/ensure-dependencies'; import { initRootBabelConfig } from '../../utils/init-root-babel-config'; import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command'; +import { addProjectToTsSolutionWorkspace } from '@nx/react/src/utils/add-app-to-pnpm-workspace'; export async function expoApplicationGenerator( host: Tree, @@ -95,6 +96,12 @@ export async function expoApplicationGeneratorInternal( : undefined ); + // If we are using the new TS solution + // We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project + if (options.useTsSolution) { + addProjectToTsSolutionWorkspace(host, options.appProjectRoot); + } + if (!options.skipFormat) { await formatFiles(host); } diff --git a/packages/expo/src/generators/library/library.ts b/packages/expo/src/generators/library/library.ts index 83743bf5a6e444..68107049918dae 100644 --- a/packages/expo/src/generators/library/library.ts +++ b/packages/expo/src/generators/library/library.ts @@ -38,6 +38,7 @@ import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-default import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command'; import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { getImportPath } from '@nx/js/src/utils/get-import-path'; +import { addProjectToTsSolutionWorkspace } from '@nx/react/src/utils/add-app-to-pnpm-workspace'; export async function expoLibraryGenerator( host: Tree, @@ -130,6 +131,10 @@ export async function expoLibraryGeneratorInternal( : undefined ); + if (options.isUsingTsSolutionConfig) { + addProjectToTsSolutionWorkspace(host, `${options.projectRoot}/*`); + } + if (!options.skipFormat) { await formatFiles(host); } diff --git a/packages/next/src/generators/application/application.ts b/packages/next/src/generators/application/application.ts index c17d968e74df5e..d7df0ea546bf91 100644 --- a/packages/next/src/generators/application/application.ts +++ b/packages/next/src/generators/application/application.ts @@ -31,6 +31,7 @@ import { showPossibleWarnings } from './lib/show-possible-warnings'; import { tsLibVersion } from '../../utils/versions'; import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command'; import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup'; +import { addProjectToTsSolutionWorkspace } from '@nx/react/src/utils/add-app-to-pnpm-workspace'; export async function applicationGenerator(host: Tree, schema: Schema) { return await applicationGeneratorInternal(host, { @@ -132,6 +133,12 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) { options.src ? 'src' : '.' ); + // If we are using the new TS solution + // We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project + if (options.useTsSolution) { + addProjectToTsSolutionWorkspace(host, options.appProjectRoot); + } + if (!options.skipFormat) { await formatFiles(host); } diff --git a/packages/next/src/generators/library/lib/normalize-options.ts b/packages/next/src/generators/library/lib/normalize-options.ts index a77b07a9623feb..cc2d85876ecc51 100644 --- a/packages/next/src/generators/library/lib/normalize-options.ts +++ b/packages/next/src/generators/library/lib/normalize-options.ts @@ -4,10 +4,12 @@ import { ensureProjectName, } from '@nx/devkit/src/generators/project-name-and-root-utils'; import { Schema } from '../schema'; +import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; export interface NormalizedSchema extends Schema { importPath: string; projectRoot: string; + isUsingTsSolutionConfig: boolean; } export async function normalizeOptions( @@ -35,5 +37,6 @@ export async function normalizeOptions( ...options, importPath, projectRoot, + isUsingTsSolutionConfig: isUsingTsSolutionSetup(host), }; } diff --git a/packages/next/src/generators/library/library.ts b/packages/next/src/generators/library/library.ts index 0269a3cf36a2cf..890a047f57d43e 100644 --- a/packages/next/src/generators/library/library.ts +++ b/packages/next/src/generators/library/library.ts @@ -16,6 +16,7 @@ import { Schema } from './schema'; import { normalizeOptions } from './lib/normalize-options'; import { eslintConfigNextVersion, tsLibVersion } from '../../utils/versions'; import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup'; +import { addProjectToTsSolutionWorkspace } from '@nx/react/src/utils/add-app-to-pnpm-workspace'; export async function libraryGenerator(host: Tree, rawOptions: Schema) { return await libraryGeneratorInternal(host, { @@ -154,6 +155,10 @@ export async function libraryGeneratorInternal(host: Tree, rawOptions: Schema) { : undefined ); + if (options.isUsingTsSolutionConfig) { + addProjectToTsSolutionWorkspace(host, `${options.projectRoot}/*`); + } + if (!options.skipFormat) { await formatFiles(host); } diff --git a/packages/react-native/src/generators/application/application.ts b/packages/react-native/src/generators/application/application.ts index 5518a43a0347a2..8109196553d89f 100644 --- a/packages/react-native/src/generators/application/application.ts +++ b/packages/react-native/src/generators/application/application.ts @@ -26,6 +26,7 @@ import { ensureDependencies } from '../../utils/ensure-dependencies'; import { syncDeps } from '../../executors/sync-deps/sync-deps.impl'; import { PackageJson } from 'nx/src/utils/package-json'; import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup'; +import { addProjectToTsSolutionWorkspace } from '@nx/react/src/utils/add-app-to-pnpm-workspace'; export async function reactNativeApplicationGenerator( host: Tree, @@ -143,6 +144,12 @@ export async function reactNativeApplicationGeneratorInternal( : undefined ); + // If we are using the new TS solution + // We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project + if (options.useTsSolution) { + addProjectToTsSolutionWorkspace(host, options.appProjectRoot); + } + if (!options.skipFormat) { await formatFiles(host); } diff --git a/packages/react-native/src/generators/library/library.ts b/packages/react-native/src/generators/library/library.ts index 227cd2d302431d..ec1afed43a386f 100644 --- a/packages/react-native/src/generators/library/library.ts +++ b/packages/react-native/src/generators/library/library.ts @@ -39,6 +39,7 @@ import { updateTsconfigFiles, } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { getImportPath } from '@nx/js/src/utils/get-import-path'; +import { addProjectToTsSolutionWorkspace } from '@nx/react/src/utils/add-app-to-pnpm-workspace'; export async function reactNativeLibraryGenerator( host: Tree, @@ -130,6 +131,10 @@ export async function reactNativeLibraryGeneratorInternal( : undefined ); + if (options.isUsingTsSolutionConfig) { + addProjectToTsSolutionWorkspace(host, `${options.projectRoot}/*`); + } + if (!options.skipFormat) { await formatFiles(host); } diff --git a/packages/react/package.json b/packages/react/package.json index e5d7f0a3348d83..9072e08551402e 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -44,7 +44,8 @@ "@nx/web": "file:../web", "@nx/module-federation": "file:../module-federation", "express": "^4.19.2", - "http-proxy-middleware": "^3.0.3" + "http-proxy-middleware": "^3.0.3", + "@zkochan/js-yaml": "0.0.7" }, "publishConfig": { "access": "public" diff --git a/packages/react/src/generators/application/application.ts b/packages/react/src/generators/application/application.ts index c9a421896e46a0..503576b052e1b1 100644 --- a/packages/react/src/generators/application/application.ts +++ b/packages/react/src/generators/application/application.ts @@ -10,6 +10,7 @@ import { setDefaults } from './lib/set-defaults'; import { addStyledModuleDependencies } from '../../rules/add-styled-dependencies'; import { addDependenciesToPackageJson, + detectPackageManager, ensurePackage, formatFiles, GeneratorCallback, @@ -41,7 +42,11 @@ import { initGenerator as jsInitGenerator } from '@nx/js'; import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command'; import { setupTailwindGenerator } from '../setup-tailwind/setup-tailwind'; import { useFlatConfig } from '@nx/eslint/src/utils/flat-config'; -import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup'; +import { + isUsingTsSolutionSetup, + updateTsconfigFiles, +} from '@nx/js/src/utils/typescript/ts-solution-setup'; +import { addProjectToTsSolutionWorkspace } from '../../utils/add-app-to-pnpm-workspace'; async function addLinting(host: Tree, options: NormalizedSchema) { const tasks: GeneratorCallback[] = []; @@ -115,7 +120,7 @@ export async function applicationGeneratorInternal( ...schema, tsConfigName: schema.rootProject ? 'tsconfig.json' : 'tsconfig.base.json', skipFormat: true, - addTsPlugin: schema.useTsSolution, + addTsPlugin: schema.useTsSolution ?? isUsingTsSolutionSetup(host), formatter: schema.formatter, }); tasks.push(jsInitTask); @@ -367,6 +372,12 @@ export async function applicationGeneratorInternal( moduleResolution: 'bundler', }); + // If we are using the new TS solution + // We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project + if (options.useTsSolution) { + addProjectToTsSolutionWorkspace(host, options.appProjectRoot); + } + if (!options.skipFormat) { await formatFiles(host); } diff --git a/packages/react/src/generators/library/lib/normalize-options.ts b/packages/react/src/generators/library/lib/normalize-options.ts index 76233f3dd833ba..9110d3f1a4d7fd 100644 --- a/packages/react/src/generators/library/lib/normalize-options.ts +++ b/packages/react/src/generators/library/lib/normalize-options.ts @@ -13,7 +13,6 @@ import { import { assertValidStyle } from '../../../utils/assertion'; import { NormalizedSchema, Schema } from '../schema'; import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; -import { promptWhenInteractive } from '@nx/devkit/src/generators/prompt'; export async function normalizeOptions( host: Tree, diff --git a/packages/react/src/generators/library/library.ts b/packages/react/src/generators/library/library.ts index cfa3e4832c3a55..9bbf8c7ff69f46 100644 --- a/packages/react/src/generators/library/library.ts +++ b/packages/react/src/generators/library/library.ts @@ -33,6 +33,7 @@ import { installCommonDependencies } from './lib/install-common-dependencies'; import { setDefaults } from './lib/set-defaults'; import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { ensureProjectIsExcludedFromPluginRegistrations } from '@nx/js/src/utils/typescript/plugin'; +import { addProjectToTsSolutionWorkspace } from '../../utils/add-app-to-pnpm-workspace'; export async function libraryGenerator(host: Tree, schema: Schema) { return await libraryGeneratorInternal(host, { @@ -278,6 +279,9 @@ export async function libraryGeneratorInternal(host: Tree, schema: Schema) { : undefined ); + if (options.isUsingTsSolutionConfig) { + addProjectToTsSolutionWorkspace(host, `${options.projectRoot}/*`); + } if (!options.skipFormat) { await formatFiles(host); } diff --git a/packages/react/src/utils/add-app-to-pnpm-workspace.ts b/packages/react/src/utils/add-app-to-pnpm-workspace.ts new file mode 100644 index 00000000000000..72b76519c21e95 --- /dev/null +++ b/packages/react/src/utils/add-app-to-pnpm-workspace.ts @@ -0,0 +1,33 @@ +import { detectPackageManager, readJson, Tree } from '@nx/devkit'; + +export function addProjectToTsSolutionWorkspace( + tree: Tree, + projectDir: string +) { + if (detectPackageManager() === 'pnpm') { + const { load, dump } = require('@zkochan/js-yaml'); + if (tree.exists('pnpm-workspace.yaml')) { + const workspaceFile = tree.read('pnpm-workspace.yaml', 'utf-8'); + const yamlData = load(workspaceFile); + + if (!yamlData?.packages) { + yamlData.packages = []; + } + + if (!yamlData.packages.includes(projectDir)) { + yamlData.packages.push(projectDir); + tree.write('pnpm-workspace.yaml', dump(yamlData, { indent: 2 })); + } + } + } else { + // Update package.json + const packageJson = readJson(tree, 'package.json'); + if (!packageJson.workspaces) { + packageJson.workspaces = []; + } + if (!packageJson.workspaces.includes(projectDir)) { + packageJson.workspaces.push(projectDir); + tree.write('package.json', JSON.stringify(packageJson, null, 2)); + } + } +} diff --git a/packages/remix/src/generators/application/application.impl.ts b/packages/remix/src/generators/application/application.impl.ts index e66b13fd2885db..108f73ef856a22 100644 --- a/packages/remix/src/generators/application/application.impl.ts +++ b/packages/remix/src/generators/application/application.impl.ts @@ -48,6 +48,7 @@ import { isUsingTsSolutionSetup, updateTsconfigFiles, } from '@nx/js/src/utils/typescript/ts-solution-setup'; +import { addProjectToTsSolutionWorkspace } from '@nx/react/src/utils/add-app-to-pnpm-workspace'; export function remixApplicationGenerator( tree: Tree, @@ -374,6 +375,12 @@ export default {...nxPreset}; '.' ); + // If we are using the new TS solution + // We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project + if (options.useTsSolution) { + addProjectToTsSolutionWorkspace(tree, options.projectRoot); + } + tasks.push(() => { logShowProjectCommand(options.projectName); }); diff --git a/packages/remix/src/generators/library/lib/normalize-options.ts b/packages/remix/src/generators/library/lib/normalize-options.ts index ebbf1ff26d0d74..1dac5a6758083d 100644 --- a/packages/remix/src/generators/library/lib/normalize-options.ts +++ b/packages/remix/src/generators/library/lib/normalize-options.ts @@ -4,10 +4,12 @@ import { ensureProjectName, } from '@nx/devkit/src/generators/project-name-and-root-utils'; import type { NxRemixGeneratorSchema } from '../schema'; +import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; export interface RemixLibraryOptions extends NxRemixGeneratorSchema { projectName: string; projectRoot: string; + isUsingTsSolutionConfig: boolean; } export async function normalizeOptions( @@ -35,5 +37,6 @@ export async function normalizeOptions( unitTestRunner: options.unitTestRunner ?? 'vitest', projectName, projectRoot, + isUsingTsSolutionConfig: isUsingTsSolutionSetup(tree), }; } diff --git a/packages/remix/src/generators/library/library.impl.ts b/packages/remix/src/generators/library/library.impl.ts index 93bb3a565948a5..b284b35df943f7 100644 --- a/packages/remix/src/generators/library/library.impl.ts +++ b/packages/remix/src/generators/library/library.impl.ts @@ -10,6 +10,7 @@ import { } from './lib'; import type { NxRemixGeneratorSchema } from './schema'; import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup'; +import { addProjectToTsSolutionWorkspace } from '@nx/react/src/utils/add-app-to-pnpm-workspace'; export async function remixLibraryGenerator( tree: Tree, @@ -73,6 +74,10 @@ export async function remixLibraryGeneratorInternal( : undefined ); + if (options.isUsingTsSolutionConfig) { + addProjectToTsSolutionWorkspace(tree, `${options.projectRoot}/*`); + } + if (!options.skipFormat) { await formatFiles(tree); } diff --git a/packages/workspace/src/generators/new/generate-workspace-files.spec.ts b/packages/workspace/src/generators/new/generate-workspace-files.spec.ts index a53182eebf46f7..bbb0ce981a8b52 100644 --- a/packages/workspace/src/generators/new/generate-workspace-files.spec.ts +++ b/packages/workspace/src/generators/new/generate-workspace-files.spec.ts @@ -332,8 +332,8 @@ describe('@nx/workspace:generateWorkspaceFiles', () => { const packageJson = tree.read('/proj/pnpm-workspace.yaml', 'utf-8'); expect(packageJson).toMatchInlineSnapshot(` "packages: - - apps/** - - packages/** + - "apps/**" + - "packages/**" " `); }); diff --git a/packages/workspace/src/generators/new/generate-workspace-files.ts b/packages/workspace/src/generators/new/generate-workspace-files.ts index da8bb757206806..951aa263dc4756 100644 --- a/packages/workspace/src/generators/new/generate-workspace-files.ts +++ b/packages/workspace/src/generators/new/generate-workspace-files.ts @@ -429,7 +429,7 @@ function setUpWorkspacesInPackageJson(tree: Tree, options: NormalizedSchema) { tree.write( join(options.directory, 'pnpm-workspace.yaml'), `packages: - - ${workspaces.join('\n - ')} + ${workspaces.map((workspace) => `- "${workspace}"`).join('\n ')} ` ); } else {