Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The `@nx/express` plugin supports the following package versions.

| Package | Supported Versions |
| --------- | ------------------ |
| `express` | ^4.21.2 |
| `express` | ^4.0.0, ^5.0.0 |

[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,19 @@ Many conventions and best practices used in Angular applications can be also be

## Requirements

The `@nx/nest` plugin depends on `@nestjs/schematics` for code generation, which pins the supported NestJS major version.
The `@nx/nest` plugin supports the following NestJS package versions.

| Nx Version | NestJS Version |
| -------------- | -------------- |
| 22.x (current) | ^11.0.0 |
| 21.x | ^11.0.0 |
| 20.x | ^10.0.0 |
| Package | Supported Versions |
| -------------- | ------------------ |
| `@nestjs/core` | ^10.0.0, ^11.0.0 |

The plugin detects the installed `@nestjs/core` major and routes the rest of the `@nestjs/*` family (plus `rxjs` and `reflect-metadata`) to versions that pair with it. Fresh installs default to NestJS v11.

| Nx Version | Default NestJS Version |
| -------------- | ---------------------- |
| 22.x (current) | ^11.0.0 |
| 21.x | ^11.0.0 |
| 20.x | ^10.0.0 |

[Nx generators](/docs/features/generate-code) install the latest supported versions automatically when scaffolding new projects.

Expand Down
3 changes: 2 additions & 1 deletion packages/express/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@
"@nx/devkit": "workspace:*",
"@nx/js": "workspace:*",
"@nx/node": "workspace:*",
"semver": "catalog:",
"tslib": "catalog:typescript"
},
"peerDependencies": {
"express": "^4.21.2"
"express": ">=4.0.0 <6.0.0"
},
"peerDependenciesMeta": {
"express": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ describe('app', () => {
expect(readJson(appTree, 'myapp/package.json')).toMatchInlineSnapshot(`
{
"dependencies": {
"express": "^4.21.2",
"express": "^5.1.0",
},
"name": "@proj/myapp",
"nx": {
Expand Down
14 changes: 11 additions & 3 deletions packages/express/src/generators/application/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { isUsingTsSolutionSetup } from '@nx/js/internal';
import { applicationGenerator as nodeApplicationGenerator } from '@nx/node';
import { tslibVersion } from '@nx/node/src/utils/versions';
import { join } from 'path';
import { assertSupportedExpressVersion } from '../../utils/assert-supported-express-version';
import { nxVersion } from '../../utils/versions';
import { initGenerator } from '../init/init';
import type { Schema } from './schema';
Expand Down Expand Up @@ -76,6 +77,8 @@ export async function applicationGenerator(tree: Tree, schema: Schema) {
}

export async function applicationGeneratorInternal(tree: Tree, schema: Schema) {
assertSupportedExpressVersion(tree);

const options = await normalizeOptions(tree, schema);

const tasks: GeneratorCallback[] = [];
Expand All @@ -92,7 +95,7 @@ export async function applicationGeneratorInternal(tree: Tree, schema: Schema) {
addTypes(tree, options);

if (!options.skipPackageJson) {
tasks.push(ensureDependencies(tree));
tasks.push(ensureDependencies(tree, options));
}

if (!options.skipFormat) {
Expand Down Expand Up @@ -132,10 +135,15 @@ async function normalizeOptions(
};
}

function ensureDependencies(tree: Tree): GeneratorCallback {
function ensureDependencies(
tree: Tree,
options: NormalizedSchema
): GeneratorCallback {
return addDependenciesToPackageJson(
tree,
{ tslib: tslibVersion },
{ '@nx/express': nxVersion }
{ '@nx/express': nxVersion },
undefined,
options.keepExistingVersions ?? true
);
}
1 change: 1 addition & 0 deletions packages/express/src/generators/application/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ export interface Schema {
setParserOptionsProject?: boolean;
addPlugin?: boolean;
useProjectJson?: boolean;
keepExistingVersions?: boolean;
}
6 changes: 6 additions & 0 deletions packages/express/src/generators/application/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@
"useProjectJson": {
"type": "boolean",
"description": "Use a `project.json` configuration file instead of inlining the Nx configuration in the `package.json` file."
},
"keepExistingVersions": {
"type": "boolean",
"x-priority": "internal",
"description": "Keep existing dependencies versions",
"default": true
}
},
"required": ["directory"]
Expand Down
15 changes: 11 additions & 4 deletions packages/express/src/generators/init/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,35 @@ import {
runTasksInSerial,
Tree,
} from '@nx/devkit';
import { expressVersion, nxVersion } from '../../utils/versions';
import { assertSupportedExpressVersion } from '../../utils/assert-supported-express-version';
import { nxVersion, versions } from '../../utils/versions';
import type { Schema } from './schema';

function updateDependencies(tree: Tree, schema: Schema) {
const tasks: GeneratorCallback[] = [];

tasks.push(removeDependenciesFromPackageJson(tree, ['@nx/express'], []));

const pkgVersions = versions(tree);
tasks.push(
addDependenciesToPackageJson(
tree,
{ express: expressVersion },
{ '@nx/express': nxVersion },
{ express: pkgVersions.expressVersion },
{
'@nx/express': nxVersion,
'@types/express': pkgVersions.expressTypingsVersion,
},
undefined,
schema.keepExistingVersions
schema.keepExistingVersions ?? true
)
);

return runTasksInSerial(...tasks);
}

export async function initGenerator(tree: Tree, schema: Schema) {
assertSupportedExpressVersion(tree);

let installTask: GeneratorCallback = () => {};
if (!schema.skipPackageJson) {
installTask = updateDependencies(tree, schema);
Expand Down
2 changes: 1 addition & 1 deletion packages/express/src/generators/init/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"type": "boolean",
"x-priority": "internal",
"description": "Keep existing dependencies versions",
"default": false
"default": true
}
},
"required": []
Expand Down
10 changes: 10 additions & 0 deletions packages/express/src/utils/all-generators-enforce-floor.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { assertGeneratorsEnforceVersionFloor } from '@nx/devkit/internal-testing-utils';
import { join } from 'node:path';

describe('@nx/express generators enforce supported version floor', () => {
assertGeneratorsEnforceVersionFloor({
packageRoot: join(__dirname, '..', '..'),
packageName: 'express',
subFloorVersion: '~3.21.0',
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { type Tree } from '@nx/devkit';
import { assertSupportedPackageVersion } from '@nx/devkit/internal';
import { minSupportedExpressVersion } from './versions';

export function assertSupportedExpressVersion(tree: Tree): void {
assertSupportedPackageVersion(tree, 'express', minSupportedExpressVersion);
}
48 changes: 46 additions & 2 deletions packages/express/src/utils/versions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,48 @@
import { type Tree } from '@nx/devkit';
import {
getDeclaredPackageVersion,
getInstalledPackageVersion,
} from '@nx/devkit/internal';
import { major } from 'semver';

export const nxVersion = require('../../package.json').version;

export const expressVersion = '^4.21.2';
export const expressTypingsVersion = '^4.17.21';
export const minSupportedExpressVersion = '4.0.0';

// Fresh-install constants (latest supported major).
export const expressVersion = '^5.1.0';
export const expressTypingsVersion = '^5.0.0';

type ExpressVersions = {
expressVersion: string;
expressTypingsVersion: string;
};

const latestVersions: ExpressVersions = {
expressVersion,
expressTypingsVersion,
};

type CompatVersions = 4;
const versionMap: Record<CompatVersions, ExpressVersions> = {
4: {
expressVersion: '^4.21.2',
expressTypingsVersion: '^4.17.21',
},
};

export function versions(tree: Tree): ExpressVersions {
const installedExpressVersion = getInstalledExpressVersion(tree);
if (!installedExpressVersion) {
return latestVersions;
}
const expressMajorVersion = major(installedExpressVersion);
return versionMap[expressMajorVersion as CompatVersions] ?? latestVersions;
}

export function getInstalledExpressVersion(tree?: Tree): string | null {
if (!tree) {
return getInstalledPackageVersion('express');
}
return getDeclaredPackageVersion(tree, 'express');
}
4 changes: 4 additions & 0 deletions packages/nest/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ export default [
'eslint',
'nest',
'@nestjs/schematics',
'@nestjs/core',
'@nestjs/common',
'reflect-metadata',
'rxjs',
],
},
],
Expand Down
21 changes: 20 additions & 1 deletion packages/nest/migrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,33 @@
"packageJsonUpdates": {
"21.2.0-beta.2": {
"version": "21.2.0-beta.2",
"requires": {
"@nestjs/core": ">=10.0.0 <11.0.0"
},
"packages": {
"nest": {
"@nestjs/common": {
"version": "^11.0.0",
"alwaysAddToPackageJson": false
},
"@nestjs/core": {
"version": "^11.0.0",
"alwaysAddToPackageJson": false
},
"@nestjs/platform-express": {
"version": "^11.0.0",
"alwaysAddToPackageJson": false
},
"@nestjs/testing": {
"version": "^11.0.0",
"alwaysAddToPackageJson": false
},
"@nestjs/schematics": {
"version": "^11.0.0",
"alwaysAddToPackageJson": false
},
"reflect-metadata": {
"version": "^0.2.0",
"alwaysAddToPackageJson": false
}
}
}
Expand Down
21 changes: 21 additions & 0 deletions packages/nest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,29 @@
"@nx/js": "workspace:*",
"@nx/eslint": "workspace:*",
"@nx/node": "workspace:*",
"semver": "catalog:",
"tslib": "catalog:typescript"
},
"peerDependencies": {
"@nestjs/core": ">=10.0.0 <12.0.0",
"@nestjs/common": ">=10.0.0 <12.0.0",
"reflect-metadata": ">=0.1.0 <0.3.0",
"rxjs": "^7.0.0"
},
"peerDependenciesMeta": {
"@nestjs/core": {
"optional": true
},
"@nestjs/common": {
"optional": true
},
"reflect-metadata": {
"optional": true
},
"rxjs": {
"optional": true
}
},
"publishConfig": {
"access": "public"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ describe('application generator', () => {
"@nestjs/common": "^11.0.0",
"@nestjs/core": "^11.0.0",
"@nestjs/platform-express": "^11.0.0",
"reflect-metadata": "^0.1.13",
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.0",
"tslib": "^2.3.0",
},
Expand Down
3 changes: 3 additions & 0 deletions packages/nest/src/generators/application/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
updateTsConfig,
} from './lib';
import type { ApplicationGeneratorOptions } from './schema';
import { assertSupportedNestJsVersion } from '../../utils/assert-supported-nestjs-version';
import { ensureDependencies } from '../../utils/ensure-dependencies';

export async function applicationGenerator(
Expand All @@ -27,6 +28,8 @@ export async function applicationGeneratorInternal(
tree: Tree,
rawOptions: ApplicationGeneratorOptions
): Promise<GeneratorCallback> {
assertSupportedNestJsVersion(tree);

const options = await normalizeOptions(tree, rawOptions);

const tasks: GeneratorCallback[] = [];
Expand Down
3 changes: 3 additions & 0 deletions packages/nest/src/generators/init/init.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import type { GeneratorCallback, Tree } from '@nx/devkit';
import { formatFiles } from '@nx/devkit';

import { assertSupportedNestJsVersion } from '../../utils/assert-supported-nestjs-version';
import { addDependencies } from './lib';
import type { InitGeneratorOptions } from './schema';

export async function initGenerator(
tree: Tree,
options: InitGeneratorOptions
): Promise<GeneratorCallback> {
assertSupportedNestJsVersion(tree);

let installPackagesTask: GeneratorCallback = () => {};
if (!options.skipPackageJson) {
installPackagesTask = addDependencies(tree, options);
Expand Down
6 changes: 3 additions & 3 deletions packages/nest/src/generators/init/lib/add-dependencies.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { GeneratorCallback, Tree } from '@nx/devkit';
import { addDependenciesToPackageJson } from '@nx/devkit';
import { nestJsSchematicsVersion, nxVersion } from '../../../utils/versions';
import { nxVersion, versions } from '../../../utils/versions';
import { InitGeneratorOptions } from '../schema';

export function addDependencies(
Expand All @@ -11,10 +11,10 @@ export function addDependencies(
tree,
{},
{
'@nestjs/schematics': nestJsSchematicsVersion,
'@nestjs/schematics': versions(tree).nestJsSchematicsVersion,
'@nx/nest': nxVersion,
},
undefined,
options.keepExistingVersions
options.keepExistingVersions ?? true
);
}
2 changes: 1 addition & 1 deletion packages/nest/src/generators/init/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"type": "boolean",
"x-priority": "internal",
"description": "Keep existing dependencies versions",
"default": false
"default": true
}
},
"required": []
Expand Down
Loading
Loading