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 9, 2024
1 parent 28c53f9 commit 664eefc
Show file tree
Hide file tree
Showing 21 changed files with 246 additions and 32 deletions.
59 changes: 59 additions & 0 deletions e2e/react/react-npm-ts-solution.test.ts
Original file line number Diff line number Diff line change
@@ -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}/*`);
});
});
62 changes: 62 additions & 0 deletions e2e/react/src/react-pnpm-ts-solution.test.ts
Original file line number Diff line number Diff line change
@@ -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}/*`);
});
});
25 changes: 1 addition & 24 deletions e2e/react/src/react.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,19 @@ 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');

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`
Expand Down Expand Up @@ -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');
Expand Down
16 changes: 15 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,
workspaces = false, // Add this temporary flag to enable ts workspaces in the new project
}: {
name?: string;
packageManager?: 'npm' | 'yarn' | 'pnpm' | 'bun';
readonly packages?: Array<NxPackage>;
workspaces?: boolean;
} = {}): string {
const newProjectStart = performance.mark('new-project:start');
try {
Expand All @@ -95,6 +97,7 @@ export function newProject({
runCreateWorkspace(projScope, {
preset: 'apps',
packageManager,
workspaces,
});
const createNxWorkspaceEnd = performance.mark('create-nx-workspace:end');
createNxWorkspaceMeasure = performance.measure(
Expand Down Expand Up @@ -228,6 +231,7 @@ export function runCreateWorkspace(
ssr,
framework,
prefix,
workspaces,
}: {
preset: string;
appName?: string;
Expand All @@ -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}`;
}
Expand Down Expand Up @@ -327,6 +335,10 @@ export function runCreateWorkspace(
command += ` --prefix=${prefix}`;
}

if (workspaces) {
command += ` --workspaces=true`;
}

try {
const create = execSync(`${command}${isVerbose() ? ' --verbose' : ''}`, {
cwd,
Expand Down Expand Up @@ -674,7 +686,9 @@ export function cleanupProject({
} catch {} // ignore crashed daemon
try {
removeSync(tmpProjPath());
} catch {}
} catch {
console.error(`Failed to remove ${tmpProjPath()}`);
}
}
resetWorkspaceContext();
}
7 changes: 7 additions & 0 deletions packages/expo/src/generators/application/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}
Expand Down
5 changes: 5 additions & 0 deletions packages/expo/src/generators/library/library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -130,6 +131,10 @@ export async function expoLibraryGeneratorInternal(
: undefined
);

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

if (!options.skipFormat) {
await formatFiles(host);
}
Expand Down
7 changes: 7 additions & 0 deletions packages/next/src/generators/application/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, {
Expand Down Expand Up @@ -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);
}
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),
};
}
5 changes: 5 additions & 0 deletions packages/next/src/generators/library/library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, {
Expand Down Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}
Expand Down
5 changes: 5 additions & 0 deletions packages/react-native/src/generators/library/library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -130,6 +131,10 @@ export async function reactNativeLibraryGeneratorInternal(
: undefined
);

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

if (!options.skipFormat) {
await formatFiles(host);
}
Expand Down
3 changes: 2 additions & 1 deletion packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Loading

0 comments on commit 664eefc

Please sign in to comment.