Skip to content

Commit

Permalink
fix(core): React workspaces that use pnpm & the new TS solution shoul…
Browse files Browse the repository at this point in the history
…d be declared correctly so that it can be referenced.
  • Loading branch information
ndcunningham committed Dec 10, 2024
1 parent 2d135f9 commit 4c07277
Show file tree
Hide file tree
Showing 20 changed files with 175 additions and 19 deletions.
7 changes: 3 additions & 4 deletions e2e/react/src/react.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
listFiles,
newProject,
readFile,
readJson,
runCLI,
runCLIAsync,
runE2ETests,
Expand All @@ -20,15 +21,13 @@ import { join } from 'path';

describe('React Applications', () => {
let proj: string;

describe('Crystal Supported Tests', () => {
beforeAll(() => {
proj = newProject({ packages: ['@nx/react'] });
ensureCypressInstallation();
});

afterAll(() => cleanupProject());

it('should be able to use Vite to build and test apps', async () => {
const appName = uniq('app');
const libName = uniq('lib');
Expand Down Expand Up @@ -68,13 +67,13 @@ describe('React Applications', () => {
const libName = uniq('lib');

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(
`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(
(plugin) => plugin.plugin === '@nx/js/typescript'
Expand Down
5 changes: 4 additions & 1 deletion e2e/utils/create-project-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,12 @@ export function newProject({
name = uniq('proj'),
packageManager = getSelectedPackageManager(),
packages,
preset = 'apps',
}: {
name?: string;
packageManager?: 'npm' | 'yarn' | 'pnpm' | 'bun';
readonly packages?: Array<NxPackage>;
preset?: string;
} = {}): string {
const newProjectStart = performance.mark('new-project:start');
try {
Expand All @@ -93,7 +95,7 @@ export function newProject({
'create-nx-workspace:start'
);
runCreateWorkspace(projScope, {
preset: 'apps',
preset,
packageManager,
});
const createNxWorkspaceEnd = performance.mark('create-nx-workspace:end');
Expand Down Expand Up @@ -256,6 +258,7 @@ export function runCreateWorkspace(
const pm = getPackageManagerCommand({ packageManager });

let command = `${pm.createWorkspace} ${name} --preset=${preset} --nxCloud=skip --no-interactive`;

if (appName) {
command += ` --appName=${appName}`;
}
Expand Down
11 changes: 10 additions & 1 deletion packages/expo/src/generators/application/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import {
Tree,
} from '@nx/devkit';
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 { addJest } from '../../utils/add-jest';
Expand Down Expand Up @@ -95,6 +98,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);
}
Expand Down
9 changes: 8 additions & 1 deletion packages/expo/src/generators/library/library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ import { ensureDependencies } from '../../utils/ensure-dependencies';
import { initRootBabelConfig } from '../../utils/init-root-babel-config';
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
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';

export async function expoLibraryGenerator(
Expand Down Expand Up @@ -130,6 +133,10 @@ export async function expoLibraryGeneratorInternal(
: undefined
);

if (options.isUsingTsSolutionConfig) {
addProjectToTsSolutionWorkspace(host, `${options.projectRoot}/*`);
}

if (!options.skipFormat) {
await formatFiles(host);
}
Expand Down
37 changes: 37 additions & 0 deletions packages/js/src/utils/typescript/ts-solution-setup.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
detectPackageManager,
joinPathFragments,
offsetFromRoot,
output,
Expand Down Expand Up @@ -186,3 +187,39 @@ export function updateTsconfigFiles(
});
}
}

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, quotingType: '"', forceQuotes: true })
);
}
}
} 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));
}
}
}
11 changes: 10 additions & 1 deletion packages/next/src/generators/application/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ import { updateCypressTsConfig } from './lib/update-cypress-tsconfig';
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,
updateTsconfigFiles,
} from '@nx/js/src/utils/typescript/ts-solution-setup';

export async function applicationGenerator(host: Tree, schema: Schema) {
return await applicationGeneratorInternal(host, {
Expand Down Expand Up @@ -132,6 +135,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);
}
Expand Down
3 changes: 3 additions & 0 deletions packages/next/src/generators/library/lib/normalize-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -35,5 +37,6 @@ export async function normalizeOptions(
...options,
importPath,
projectRoot,
isUsingTsSolutionConfig: isUsingTsSolutionSetup(host),
};
}
9 changes: 8 additions & 1 deletion packages/next/src/generators/library/library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ import { nextInitGenerator } from '../init/init';
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,
updateTsconfigFiles,
} from '@nx/js/src/utils/typescript/ts-solution-setup';

export async function libraryGenerator(host: Tree, rawOptions: Schema) {
return await libraryGeneratorInternal(host, {
Expand Down Expand Up @@ -154,6 +157,10 @@ export async function libraryGeneratorInternal(host: Tree, rawOptions: Schema) {
: undefined
);

if (options.isUsingTsSolutionConfig) {
addProjectToTsSolutionWorkspace(host, `${options.projectRoot}/*`);
}

if (!options.skipFormat) {
await formatFiles(host);
}
Expand Down
11 changes: 10 additions & 1 deletion packages/react-native/src/generators/application/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ import { Schema } from './schema';
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,
updateTsconfigFiles,
} from '@nx/js/src/utils/typescript/ts-solution-setup';

export async function reactNativeApplicationGenerator(
host: Tree,
Expand Down Expand Up @@ -143,6 +146,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);
}
Expand Down
6 changes: 5 additions & 1 deletion packages/react-native/src/generators/library/library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { Schema } from './schema';
import { ensureDependencies } from '../../utils/ensure-dependencies';
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
import {
isUsingTsSolutionSetup,
addProjectToTsSolutionWorkspace,
updateTsconfigFiles,
} from '@nx/js/src/utils/typescript/ts-solution-setup';
import { getImportPath } from '@nx/js/src/utils/get-import-path';
Expand Down Expand Up @@ -130,6 +130,10 @@ export async function reactNativeLibraryGeneratorInternal(
: undefined
);

if (options.isUsingTsSolutionConfig) {
addProjectToTsSolutionWorkspace(host, `${options.projectRoot}/*`);
}

if (!options.skipFormat) {
await formatFiles(host);
}
Expand Down
19 changes: 19 additions & 0 deletions packages/react/src/generators/application/application.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { Linter } from '@nx/eslint';
import { applicationGenerator } from './application';
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
// which is v9 while we are testing for the new v10 version
jest.mock('@nx/cypress/src/utils/cypress-version');
Expand Down Expand Up @@ -1247,6 +1248,7 @@ describe('app', () => {
describe('TS solution setup', () => {
beforeEach(() => {
appTree = createTreeWithEmptyWorkspace();
appTree.write('pnpm-workspace.yaml', `packages:`);
updateJson(appTree, 'package.json', (json) => {
json.workspaces = ['packages/*', 'apps/*'];
return json;
Expand Down Expand Up @@ -1418,5 +1420,22 @@ describe('app', () => {
}
`);
});

it('should add project to workspaces when using TS solution', async () => {
await applicationGenerator(appTree, {
directory: 'myapp',
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']);
});
});
});
15 changes: 13 additions & 2 deletions packages/react/src/generators/application/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { setDefaults } from './lib/set-defaults';
import { addStyledModuleDependencies } from '../../rules/add-styled-dependencies';
import {
addDependenciesToPackageJson,
detectPackageManager,
ensurePackage,
formatFiles,
GeneratorCallback,
Expand Down Expand Up @@ -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 {
addProjectToTsSolutionWorkspace,
isUsingTsSolutionSetup,
updateTsconfigFiles,
} from '@nx/js/src/utils/typescript/ts-solution-setup';

async function addLinting(host: Tree, options: NormalizedSchema) {
const tasks: GeneratorCallback[] = [];
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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.isUsingTsSolutionConfig) {
addProjectToTsSolutionWorkspace(host, options.appProjectRoot);
}

if (!options.skipFormat) {
await formatFiles(host);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading

0 comments on commit 4c07277

Please sign in to comment.