fix(core): Adding react apps/libs to workspaces so they can be referenced. (#29202)

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- 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
<!-- This is the behavior we have today -->
This PR address a few things:

1. When we generate an app or a library using the new TS Solution they
are not added to the workspaces/packages option.
2. Currently, when we use `pnpm` to generate a workspace the
`pnpm-workspace.yaml` looks like below which is not correct
```
packages: 
  - packages/**
```

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

1. Libraries and apps should be referenced correctly out of the box so
that they can be symlinked after installation.
2. The intended `pnpm-workspace.yaml` should look similar to:
```
packages: 
  - 'packages/**'
  - 'demo'
```

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

---------

Co-authored-by: Jack Hsu <jack.hsu@gmail.com>
This commit is contained in:
Nicholas Cunningham 2024-12-18 10:39:47 -07:00 committed by GitHub
parent 4b586a1acc
commit d05f30fb01
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 241 additions and 29 deletions

View File

@ -79,7 +79,7 @@ describe('@nx/expo (legacy)', () => {
it('should serve with metro', async () => { it('should serve with metro', async () => {
let process: ChildProcess; let process: ChildProcess;
const port = 8081; const port = 8051;
try { try {
process = await runCommandUntil( process = await runCommandUntil(
@ -168,16 +168,17 @@ describe('@nx/expo (legacy)', () => {
}); });
it('should start', async () => { it('should start', async () => {
const port = 8041;
// run start command // run start command
const startProcess = await runCommandUntil( const startProcess = await runCommandUntil(
`start ${appName} -- --port=8081`, `start ${appName} -- --port=${port}`,
(output) => output.includes(`http://localhost:8081`) (output) => output.includes(`http://localhost:${port}`)
); );
// port and process cleanup // port and process cleanup
try { try {
await promisifiedTreeKill(startProcess.pid, 'SIGKILL'); await promisifiedTreeKill(startProcess.pid, 'SIGKILL');
await killPorts(8081); await killPorts(port);
} catch (err) { } catch (err) {
expect(err).toBeFalsy(); expect(err).toBeFalsy();
} }

View File

@ -55,12 +55,12 @@ describe('@nx/expo', () => {
it('should start the app', async () => { it('should start the app', async () => {
let process: ChildProcess; let process: ChildProcess;
const port = 8081; const port = 8088;
try { try {
process = await runCommandUntil( process = await runCommandUntil(
`start ${appName} -- --port=${port}`, `start ${appName} -- --port=${port}`,
(output) => output.includes(`http://localhost:8081`) (output) => output.includes(`http://localhost:8088`)
); );
} catch (err) { } catch (err) {
console.error(err); console.error(err);
@ -74,12 +74,12 @@ describe('@nx/expo', () => {
it('should serve the app', async () => { it('should serve the app', async () => {
let process: ChildProcess; let process: ChildProcess;
const port = 8081; const port = 8071;
try { try {
process = await runCommandUntil( process = await runCommandUntil(
`serve ${appName} -- --port=${port}`, `serve ${appName} -- --port=${port}`,
(output) => output.includes(`http://localhost:8081`) (output) => output.includes(`http://localhost:8071`)
); );
} catch (err) { } catch (err) {
console.error(err); console.error(err);

View File

@ -8,6 +8,7 @@ import {
listFiles, listFiles,
newProject, newProject,
readFile, readFile,
readJson,
runCLI, runCLI,
runCLIAsync, runCLIAsync,
runE2ETests, runE2ETests,
@ -20,7 +21,6 @@ import { join } from 'path';
describe('React Applications', () => { describe('React Applications', () => {
let proj: string; let proj: string;
describe('Crystal Supported Tests', () => { describe('Crystal Supported Tests', () => {
beforeAll(() => { beforeAll(() => {
proj = newProject({ packages: ['@nx/react'] }); proj = newProject({ packages: ['@nx/react'] });
@ -28,7 +28,6 @@ describe('React Applications', () => {
}); });
afterAll(() => cleanupProject()); afterAll(() => cleanupProject());
it('should be able to use Vite to build and test apps', async () => { it('should be able to use Vite to build and test apps', async () => {
const appName = uniq('app'); const appName = uniq('app');
const libName = uniq('lib'); const libName = uniq('lib');
@ -68,13 +67,13 @@ describe('React Applications', () => {
const libName = uniq('lib'); const libName = uniq('lib');
runCLI( runCLI(
`generate @nx/react:app apps/${appName} --name=${appName} --useTsSolution true --bundler=vite --no-interactive --skipFormat --linter=eslint --unitTestRunner=vitest` `generate @nx/react:app apps/${appName} --name=${appName} --useTsSolution=true --bundler=vite --no-interactive --skipFormat --linter=eslint --unitTestRunner=vitest`
); );
runCLI( runCLI(
`generate @nx/react:lib ${libName} --bundler=none --no-interactive --unit-test-runner=vitest --skipFormat --linter=eslint` `generate @nx/react:lib ${libName} --bundler=none --no-interactive --unit-test-runner=vitest --skipFormat --linter=eslint`
); );
const nxJson = JSON.parse(readFile('nx.json')); const nxJson = readJson('nx.json');
const jsTypescriptPlugin = nxJson.plugins.find( const jsTypescriptPlugin = nxJson.plugins.find(
(plugin) => plugin.plugin === '@nx/js/typescript' (plugin) => plugin.plugin === '@nx/js/typescript'

View File

@ -258,6 +258,7 @@ export function runCreateWorkspace(
const pm = getPackageManagerCommand({ packageManager }); const pm = getPackageManagerCommand({ packageManager });
let command = `${pm.createWorkspace} ${name} --preset=${preset} --nxCloud=skip --no-interactive`; let command = `${pm.createWorkspace} ${name} --preset=${preset} --nxCloud=skip --no-interactive`;
if (appName) { if (appName) {
command += ` --appName=${appName}`; command += ` --appName=${appName}`;
} }

View File

@ -6,7 +6,10 @@ import {
Tree, Tree,
} from '@nx/devkit'; } from '@nx/devkit';
import { initGenerator as jsInitGenerator } from '@nx/js'; import { initGenerator as jsInitGenerator } from '@nx/js';
import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup'; import {
addProjectToTsSolutionWorkspace,
updateTsconfigFiles,
} from '@nx/js/src/utils/typescript/ts-solution-setup';
import { addLinting } from '../../utils/add-linting'; import { addLinting } from '../../utils/add-linting';
import { addJest } from '../../utils/add-jest'; import { addJest } from '../../utils/add-jest';
@ -95,6 +98,12 @@ export async function expoApplicationGeneratorInternal(
: undefined : 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) { if (!options.skipFormat) {
await formatFiles(host); await formatFiles(host);
} }

View File

@ -36,7 +36,10 @@ import { ensureDependencies } from '../../utils/ensure-dependencies';
import { initRootBabelConfig } from '../../utils/init-root-babel-config'; import { initRootBabelConfig } from '../../utils/init-root-babel-config';
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils'; import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command'; import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup'; import {
addProjectToTsSolutionWorkspace,
updateTsconfigFiles,
} from '@nx/js/src/utils/typescript/ts-solution-setup';
import { getImportPath } from '@nx/js/src/utils/get-import-path'; import { getImportPath } from '@nx/js/src/utils/get-import-path';
export async function expoLibraryGenerator( export async function expoLibraryGenerator(
@ -130,6 +133,10 @@ export async function expoLibraryGeneratorInternal(
: undefined : undefined
); );
if (options.isUsingTsSolutionConfig) {
addProjectToTsSolutionWorkspace(host, options.projectRoot);
}
if (!options.skipFormat) { if (!options.skipFormat) {
await formatFiles(host); await formatFiles(host);
} }

View File

@ -10,7 +10,7 @@ import {
} from '@nx/devkit'; } from '@nx/devkit';
import { FsTree } from 'nx/src/generators/tree'; import { FsTree } from 'nx/src/generators/tree';
import { isUsingPackageManagerWorkspaces } from '../package-manager-workspaces'; import { isUsingPackageManagerWorkspaces } from '../package-manager-workspaces';
import { basename, join, relative } from 'node:path/posix'; import { basename, dirname, join, relative } from 'node:path/posix';
export function isUsingTypeScriptPlugin(tree: Tree): boolean { export function isUsingTypeScriptPlugin(tree: Tree): boolean {
const nxJson = readNxJson(tree); const nxJson = readNxJson(tree);
@ -204,3 +204,41 @@ export function updateTsconfigFiles(
}); });
} }
} }
export function addProjectToTsSolutionWorkspace(
tree: Tree,
projectDir: string
) {
// If dir is "libs/foo" then use "libs/**" so we don't need so many entries in the workspace file.
// If the dir is just "foo" then we have to add it as is.
const baseDir = dirname(projectDir);
const pattern = baseDir === '.' ? projectDir : `${baseDir}/**`;
if (tree.exists('pnpm-workspace.yaml')) {
const { load, dump } = require('@zkochan/js-yaml');
const workspaceFile = tree.read('pnpm-workspace.yaml', 'utf-8');
const yamlData = load(workspaceFile);
if (!yamlData?.packages) {
yamlData.packages = [];
}
if (!yamlData.packages.includes(pattern)) {
yamlData.packages.push(pattern);
tree.write(
'pnpm-workspace.yaml',
dump(yamlData, { indent: 2, quotingType: '"', forceQuotes: true })
);
}
} else {
// Update package.json
const packageJson = readJson(tree, 'package.json');
if (!packageJson.workspaces) {
packageJson.workspaces = [];
}
if (!packageJson.workspaces.includes(pattern)) {
packageJson.workspaces.push(pattern);
tree.write('package.json', JSON.stringify(packageJson, null, 2));
}
}
}

View File

@ -30,7 +30,10 @@ import { updateCypressTsConfig } from './lib/update-cypress-tsconfig';
import { showPossibleWarnings } from './lib/show-possible-warnings'; import { showPossibleWarnings } from './lib/show-possible-warnings';
import { tsLibVersion } from '../../utils/versions'; import { tsLibVersion } from '../../utils/versions';
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command'; import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup'; import {
addProjectToTsSolutionWorkspace,
updateTsconfigFiles,
} from '@nx/js/src/utils/typescript/ts-solution-setup';
export async function applicationGenerator(host: Tree, schema: Schema) { export async function applicationGenerator(host: Tree, schema: Schema) {
return await applicationGeneratorInternal(host, { return await applicationGeneratorInternal(host, {
@ -132,6 +135,12 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
options.src ? 'src' : '.' 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) { if (!options.skipFormat) {
await formatFiles(host); await formatFiles(host);
} }

View File

@ -4,10 +4,12 @@ import {
ensureProjectName, ensureProjectName,
} from '@nx/devkit/src/generators/project-name-and-root-utils'; } from '@nx/devkit/src/generators/project-name-and-root-utils';
import { Schema } from '../schema'; import { Schema } from '../schema';
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
export interface NormalizedSchema extends Schema { export interface NormalizedSchema extends Schema {
importPath: string; importPath: string;
projectRoot: string; projectRoot: string;
isUsingTsSolutionConfig: boolean;
} }
export async function normalizeOptions( export async function normalizeOptions(
@ -35,5 +37,6 @@ export async function normalizeOptions(
...options, ...options,
importPath, importPath,
projectRoot, projectRoot,
isUsingTsSolutionConfig: isUsingTsSolutionSetup(host),
}; };
} }

View File

@ -17,6 +17,7 @@ import { normalizeOptions } from './lib/normalize-options';
import { eslintConfigNextVersion, tsLibVersion } from '../../utils/versions'; import { eslintConfigNextVersion, tsLibVersion } from '../../utils/versions';
import { import {
isUsingTsSolutionSetup, isUsingTsSolutionSetup,
addProjectToTsSolutionWorkspace,
updateTsconfigFiles, updateTsconfigFiles,
} from '@nx/js/src/utils/typescript/ts-solution-setup'; } from '@nx/js/src/utils/typescript/ts-solution-setup';
@ -161,6 +162,10 @@ export async function libraryGeneratorInternal(host: Tree, rawOptions: Schema) {
: undefined : undefined
); );
if (options.isUsingTsSolutionConfig) {
addProjectToTsSolutionWorkspace(host, options.projectRoot);
}
if (!options.skipFormat) { if (!options.skipFormat) {
await formatFiles(host); await formatFiles(host);
} }

View File

@ -25,7 +25,10 @@ import { Schema } from './schema';
import { ensureDependencies } from '../../utils/ensure-dependencies'; import { ensureDependencies } from '../../utils/ensure-dependencies';
import { syncDeps } from '../../executors/sync-deps/sync-deps.impl'; import { syncDeps } from '../../executors/sync-deps/sync-deps.impl';
import { PackageJson } from 'nx/src/utils/package-json'; import { PackageJson } from 'nx/src/utils/package-json';
import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup'; import {
addProjectToTsSolutionWorkspace,
updateTsconfigFiles,
} from '@nx/js/src/utils/typescript/ts-solution-setup';
export async function reactNativeApplicationGenerator( export async function reactNativeApplicationGenerator(
host: Tree, host: Tree,
@ -143,6 +146,12 @@ export async function reactNativeApplicationGeneratorInternal(
: undefined : 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) { if (!options.skipFormat) {
await formatFiles(host); await formatFiles(host);
} }

View File

@ -34,7 +34,10 @@ import { NormalizedSchema, normalizeOptions } from './lib/normalize-options';
import { Schema } from './schema'; import { Schema } from './schema';
import { ensureDependencies } from '../../utils/ensure-dependencies'; import { ensureDependencies } from '../../utils/ensure-dependencies';
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command'; import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup'; import {
addProjectToTsSolutionWorkspace,
updateTsconfigFiles,
} from '@nx/js/src/utils/typescript/ts-solution-setup';
import { getImportPath } from '@nx/js/src/utils/get-import-path'; import { getImportPath } from '@nx/js/src/utils/get-import-path';
export async function reactNativeLibraryGenerator( export async function reactNativeLibraryGenerator(
@ -127,6 +130,10 @@ export async function reactNativeLibraryGeneratorInternal(
: undefined : undefined
); );
if (options.isUsingTsSolutionConfig) {
addProjectToTsSolutionWorkspace(host, options.projectRoot);
}
if (!options.skipFormat) { if (!options.skipFormat) {
await formatFiles(host); await formatFiles(host);
} }

View File

@ -15,6 +15,8 @@ import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { Linter } from '@nx/eslint'; import { Linter } from '@nx/eslint';
import { applicationGenerator } from './application'; import { applicationGenerator } from './application';
import { Schema } from './schema'; import { Schema } from './schema';
const { load } = require('@zkochan/js-yaml');
// need to mock cypress otherwise it'll use the nx installed version from package.json // need to mock cypress otherwise it'll use the nx installed version from package.json
// which is v9 while we are testing for the new v10 version // which is v9 while we are testing for the new v10 version
jest.mock('@nx/cypress/src/utils/cypress-version'); jest.mock('@nx/cypress/src/utils/cypress-version');
@ -1277,7 +1279,7 @@ describe('app', () => {
beforeEach(() => { beforeEach(() => {
appTree = createTreeWithEmptyWorkspace(); appTree = createTreeWithEmptyWorkspace();
updateJson(appTree, 'package.json', (json) => { updateJson(appTree, 'package.json', (json) => {
json.workspaces = ['packages/*', 'apps/*']; json.workspaces = ['packages/**', 'apps/**'];
return json; return json;
}); });
writeJson(appTree, 'tsconfig.base.json', { writeJson(appTree, 'tsconfig.base.json', {
@ -1453,6 +1455,81 @@ describe('app', () => {
} }
`); `);
}); });
it('should add project to workspaces when using TS solution (npm, yarn, bun)', async () => {
await applicationGenerator(appTree, {
directory: 'myapp',
addPlugin: true,
linter: Linter.EsLint,
style: 'none',
bundler: 'vite',
unitTestRunner: 'none',
e2eTestRunner: 'none',
});
await applicationGenerator(appTree, {
directory: 'libs/nested1',
addPlugin: true,
linter: Linter.EsLint,
style: 'none',
bundler: 'vite',
unitTestRunner: 'none',
e2eTestRunner: 'none',
});
await applicationGenerator(appTree, {
directory: 'libs/nested2',
addPlugin: true,
linter: Linter.EsLint,
style: 'none',
bundler: 'vite',
unitTestRunner: 'none',
e2eTestRunner: 'none',
});
const packageJson = readJson(appTree, 'package.json');
expect(packageJson.workspaces).toEqual([
'packages/**',
'apps/**',
'myapp',
'libs/**',
]);
});
it('should add project to workspaces when using TS solution (pnpm)', async () => {
appTree.write('pnpm-workspace.yaml', `packages:`);
await applicationGenerator(appTree, {
directory: 'myapp',
addPlugin: true,
linter: Linter.EsLint,
style: 'none',
bundler: 'vite',
unitTestRunner: 'none',
e2eTestRunner: 'none',
});
await applicationGenerator(appTree, {
directory: 'apps/nested1',
addPlugin: true,
linter: Linter.EsLint,
style: 'none',
bundler: 'vite',
unitTestRunner: 'none',
e2eTestRunner: 'none',
});
await applicationGenerator(appTree, {
directory: 'apps/nested2',
addPlugin: true,
linter: Linter.EsLint,
style: 'none',
bundler: 'vite',
unitTestRunner: 'none',
e2eTestRunner: 'none',
});
const pnpmContent = appTree.read('pnpm-workspace.yaml', 'utf-8');
const pnpmWorkspaceFile = load(pnpmContent);
expect(pnpmWorkspaceFile.packages).toEqual(['myapp', 'apps/**']);
});
}); });
describe('--bundler=rsbuild', () => { describe('--bundler=rsbuild', () => {

View File

@ -9,7 +9,10 @@ import {
} from '@nx/devkit'; } from '@nx/devkit';
import { initGenerator as jsInitGenerator } from '@nx/js'; import { initGenerator as jsInitGenerator } from '@nx/js';
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command'; import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup'; import {
addProjectToTsSolutionWorkspace,
updateTsconfigFiles,
} from '@nx/js/src/utils/typescript/ts-solution-setup';
import { extractTsConfigBase } from '../../utils/create-ts-config'; import { extractTsConfigBase } from '../../utils/create-ts-config';
import { addStyledModuleDependencies } from '../../rules/add-styled-dependencies'; import { addStyledModuleDependencies } from '../../rules/add-styled-dependencies';
import { setupTailwindGenerator } from '../setup-tailwind/setup-tailwind'; import { setupTailwindGenerator } from '../setup-tailwind/setup-tailwind';
@ -174,6 +177,12 @@ export async function applicationGeneratorInternal(
: undefined : 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.isUsingTsSolutionConfig) {
addProjectToTsSolutionWorkspace(tree, options.appProjectRoot);
}
if (!options.skipFormat) { if (!options.skipFormat) {
await formatFiles(tree); await formatFiles(tree);
} }

View File

@ -13,7 +13,6 @@ import {
import { assertValidStyle } from '../../../utils/assertion'; import { assertValidStyle } from '../../../utils/assertion';
import { NormalizedSchema, Schema } from '../schema'; import { NormalizedSchema, Schema } from '../schema';
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
import { promptWhenInteractive } from '@nx/devkit/src/generators/prompt';
export async function normalizeOptions( export async function normalizeOptions(
host: Tree, host: Tree,

View File

@ -15,6 +15,7 @@ import { nxVersion } from '../../utils/versions';
import applicationGenerator from '../application/application'; import applicationGenerator from '../application/application';
import libraryGenerator from './library'; import libraryGenerator from './library';
import { Schema } from './schema'; import { Schema } from './schema';
const { load } = require('@zkochan/js-yaml');
// need to mock cypress otherwise it'll use the nx installed version from package.json // need to mock cypress otherwise it'll use the nx installed version from package.json
// which is v9 while we are testing for the new v10 version // which is v9 while we are testing for the new v10 version
jest.mock('@nx/cypress/src/utils/cypress-version'); jest.mock('@nx/cypress/src/utils/cypress-version');
@ -1215,11 +1216,10 @@ module.exports = withNx(
await libraryGenerator(tree, { await libraryGenerator(tree, {
...defaultSchema, ...defaultSchema,
bundler: 'rollup', bundler: 'rollup',
publishable: true,
importPath: '@acme/mylib',
unitTestRunner: 'none',
directory: 'mylib', directory: 'mylib',
name: 'mylib', name: 'mylib',
publishable: true,
importPath: '@acme/mylib',
}); });
expect(readJson(tree, 'mylib/package.json')).toMatchInlineSnapshot(` expect(readJson(tree, 'mylib/package.json')).toMatchInlineSnapshot(`
@ -1249,5 +1249,21 @@ module.exports = withNx(
} }
`); `);
}); });
it('should add project to workspaces when using TS solution', async () => {
tree.write('pnpm-workspace.yaml', `packages:`);
await libraryGenerator(tree, {
...defaultSchema,
bundler: 'rollup',
unitTestRunner: 'none',
directory: 'mylib',
name: 'mylib',
});
const pnpmContent = tree.read('pnpm-workspace.yaml', 'utf-8');
const pnpmWorkspaceFile = load(pnpmContent);
expect(pnpmWorkspaceFile.packages).toEqual(['mylib']);
});
}); });
}); });

View File

@ -31,7 +31,10 @@ import { createFiles } from './lib/create-files';
import { extractTsConfigBase } from '../../utils/create-ts-config'; import { extractTsConfigBase } from '../../utils/create-ts-config';
import { installCommonDependencies } from './lib/install-common-dependencies'; import { installCommonDependencies } from './lib/install-common-dependencies';
import { setDefaults } from './lib/set-defaults'; import { setDefaults } from './lib/set-defaults';
import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup'; import {
addProjectToTsSolutionWorkspace,
updateTsconfigFiles,
} from '@nx/js/src/utils/typescript/ts-solution-setup';
import { ensureProjectIsExcludedFromPluginRegistrations } from '@nx/js/src/utils/typescript/plugin'; import { ensureProjectIsExcludedFromPluginRegistrations } from '@nx/js/src/utils/typescript/plugin';
export async function libraryGenerator(host: Tree, schema: Schema) { export async function libraryGenerator(host: Tree, schema: Schema) {
@ -280,6 +283,9 @@ export async function libraryGeneratorInternal(host: Tree, schema: Schema) {
: undefined : undefined
); );
if (options.isUsingTsSolutionConfig) {
addProjectToTsSolutionWorkspace(host, options.projectRoot);
}
if (!options.skipFormat) { if (!options.skipFormat) {
await formatFiles(host); await formatFiles(host);
} }

View File

@ -45,6 +45,7 @@ import {
} from './lib'; } from './lib';
import { NxRemixGeneratorSchema } from './schema'; import { NxRemixGeneratorSchema } from './schema';
import { import {
addProjectToTsSolutionWorkspace,
isUsingTsSolutionSetup, isUsingTsSolutionSetup,
updateTsconfigFiles, updateTsconfigFiles,
} from '@nx/js/src/utils/typescript/ts-solution-setup'; } from '@nx/js/src/utils/typescript/ts-solution-setup';
@ -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(() => { tasks.push(() => {
logShowProjectCommand(options.projectName); logShowProjectCommand(options.projectName);
}); });

View File

@ -4,10 +4,12 @@ import {
ensureProjectName, ensureProjectName,
} from '@nx/devkit/src/generators/project-name-and-root-utils'; } from '@nx/devkit/src/generators/project-name-and-root-utils';
import type { NxRemixGeneratorSchema } from '../schema'; import type { NxRemixGeneratorSchema } from '../schema';
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
export interface RemixLibraryOptions extends NxRemixGeneratorSchema { export interface RemixLibraryOptions extends NxRemixGeneratorSchema {
projectName: string; projectName: string;
projectRoot: string; projectRoot: string;
isUsingTsSolutionConfig: boolean;
} }
export async function normalizeOptions( export async function normalizeOptions(
@ -35,5 +37,6 @@ export async function normalizeOptions(
unitTestRunner: options.unitTestRunner ?? 'vitest', unitTestRunner: options.unitTestRunner ?? 'vitest',
projectName, projectName,
projectRoot, projectRoot,
isUsingTsSolutionConfig: isUsingTsSolutionSetup(tree),
}; };
} }

View File

@ -9,7 +9,10 @@ import {
updateBuildableConfig, updateBuildableConfig,
} from './lib'; } from './lib';
import type { NxRemixGeneratorSchema } from './schema'; import type { NxRemixGeneratorSchema } from './schema';
import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup'; import {
addProjectToTsSolutionWorkspace,
updateTsconfigFiles,
} from '@nx/js/src/utils/typescript/ts-solution-setup';
export async function remixLibraryGenerator( export async function remixLibraryGenerator(
tree: Tree, tree: Tree,
@ -73,6 +76,10 @@ export async function remixLibraryGeneratorInternal(
: undefined : undefined
); );
if (options.isUsingTsSolutionConfig) {
addProjectToTsSolutionWorkspace(tree, options.projectRoot);
}
if (!options.skipFormat) { if (!options.skipFormat) {
await formatFiles(tree); await formatFiles(tree);
} }

View File

@ -332,8 +332,8 @@ describe('@nx/workspace:generateWorkspaceFiles', () => {
const packageJson = tree.read('/proj/pnpm-workspace.yaml', 'utf-8'); const packageJson = tree.read('/proj/pnpm-workspace.yaml', 'utf-8');
expect(packageJson).toMatchInlineSnapshot(` expect(packageJson).toMatchInlineSnapshot(`
"packages: "packages:
- apps/** - "apps/**"
- packages/** - "packages/**"
" "
`); `);
}); });

View File

@ -433,7 +433,7 @@ function setUpWorkspacesInPackageJson(tree: Tree, options: NormalizedSchema) {
tree.write( tree.write(
join(options.directory, 'pnpm-workspace.yaml'), join(options.directory, 'pnpm-workspace.yaml'),
`packages: `packages:
- ${workspaces.join('\n - ')} ${workspaces.map((workspace) => `- "${workspace}"`).join('\n ')}
` `
); );
} else { } else {