master
576 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
ee0bc60a33 |
fix(misc): move plugin internal imports to devkit/internal (#36430)
## Current Behavior
First-party plugins reach into `nx` internals through deep subpaths
(`nx/src/executors/run-commands/run-commands.impl`,
`nx/src/generators/tree`, `nx/src/plugins/js/lock-file/lock-file`, …),
so there is no single boundary between the plugins and nx's internal
module layout.
## Expected Behavior
Those imports are routed through the `@nx/devkit/internal` barrel, and a
lint rule enforces the boundary. `nx/release` stays exempt as a public,
stable entry point for release-extension plugins.
### Note on `packages/nest/test-setup.ts`
This one is a latent-bug fix, not lint appeasement. The previous setup
installed the project-graph stub with
`jest.spyOn(require('nx/src/project-graph/project-graph'),
'createProjectGraphAsync')` at module scope. `jest.restoreAllMocks()`
undoes anything installed via `jest.spyOn`, and four nest suites —
`init`, `library`, `application` and `run-nest-schematic` — call it from
an `afterAll` hook. Since `test-setup.ts` is wired in through
`setupFilesAfterEnv` and runs once per test file, that `afterAll` tore
the stub down for the rest of the file, so any later `describe` block
silently fell through to the **real** `createProjectGraphAsync` instead
of the stub. Switching to a `jest.mock(...)` module factory fixes it:
module-registry substitution is not affected by `restoreAllMocks()`, so
the stub now survives the whole file as intended.
## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->
Fixes NXC-4748
---------
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
|
||
|
|
44706cdfa2 |
fix(linter): use projectService for typed linting in flat configs (#35727)
## Current Behavior
Nx's ESLint generators emit typed-linting config using the legacy
`parserOptions.project` array regardless of the eslint config kind:
```js
languageOptions: {
parserOptions: {
project: ['apps/products/tsconfig.*?.json'],
},
},
```
In flat configs, this has two recurring problems:
1. In TS solution-style workspaces, cross-project imports resolve to the
referenced project's `out-tsc/*.d.ts` output rather than `src/*.ts`,
which surfaces as `unexpectedReads` of dependency projects' declarations
during task-sandboxed `lint` runs.
2. Files outside any listed tsconfig fail with the classic "ESLint was
configured to run ... however none of those TSConfigs include this file"
error, forcing `ignores` / `.eslintignore` workarounds.
The flag for opting into typed linting is also named after its low-level
emission detail (`setParserOptionsProject`), which is no longer
accurate.
## Expected Behavior
For flat configs, generators emit typescript-eslint's recommended
project-service shape:
```js
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname, // or `__dirname` for cjs
},
},
```
The project service resolves project references to source and handles
out-of-project files gracefully, fixing both issues above.
Legacy `.eslintrc` configs keep emitting `parserOptions.project`. They
are JSON, which cannot express the `__dirname` that `tsconfigRootDir`
needs.
A new generic `enableTypedLinting` flag replaces
`setParserOptionsProject`, which is deprecated for removal in v24. Both
flags behave identically during the deprecation window; users on the
deprecated flag get the new emission automatically.
## Implementation Details
- New `enableTypedLinting?: boolean` option added to every
ESLint-related generator schema. `setParserOptionsProject` marked
`x-deprecated` (schema.json) and `@deprecated` (schema.d.ts).
- New `isTypedLintingEnabled(options)` helper exported from `@nx/eslint`
centralizes the merge between the new and deprecated flags. Generators
normalize at the forwarding boundary so downstream calls receive a
single normalized flag.
- New AST helpers `generateProjectServiceParserOptions(format)` and
`generateTypedLintingFlatConfigOverride(format)` emit the projectService
block with `import.meta.dirname` (mjs) or `__dirname` (cjs).
- New `addTypedLintingToFlatConfig(tree, root)` re-emits the
projectService block after operations that strip overrides (e.g. cypress
`replaceOverridesInLintConfig`).
- New `inspectTypedLinting(content)` helper reports what a config
already configures for typed linting: `projectService`, the legacy
`parserOptions.project`, an explicit `projectService: false` opt-out, or
nothing. Angular `add-linting` uses it instead of the brittle
`tsconfig.*?.json` literal string match. It walks the exported config
value structurally, resolving const bindings, member access, ES
shorthand, wrapper calls like `tseslint.config(...)`, and the local
arrays a config spreads in, so parser options assembled indirectly are
still recognized.
- When a local `parserOptions` is built from an expression the walk
cannot read statically (a call, an imported reference, a dynamic key),
typed linting is left undecided, so the generator warns and leaves the
config unchanged rather than appending a block that could silently
convert a `project` setup to the project service. A config that only
spreads in another file has no local `parserOptions` of its own and
stays safe to append to.
- The appended block always sets `project: null` next to
`projectService: true`. ESLint merges `parserOptions` across flat config
entries and typescript-eslint rejects a merged truthy `project` beside
`projectService`, so a `project` inherited from a base config the
workspace spreads in would otherwise turn every type-checked file into a
parsing error. `project: null` wins that merge and is inert. Before this
change the generators emitted `project` themselves, so the combination
could not arise.
- A legacy config is read as JSON, JS or YAML. A bare `.eslintrc` can be
any of the three and takes precedence over every other config filename,
so reading only the first two dropped an existing
`parserOptions.project` when `@nx/angular:add-linting` carried it across
an override rewrite.
- The module system of a flat config is taken from its extension where
the extension is decisive (`.cts`, `.mts`), not from its content. An
`eslint.config.cts` written idiomatically with `export default` used to
read as ESM, so its typed-linting block got `tsconfigRootDir:
import.meta.dirname` and an added override got `parser: await
import(...)` (a top-level await), both of which its CommonJS output
rejects. The typed-linting path, `addOverrideToLintConfig`, and
`replaceOverridesInLintConfig` all derive the format from the extension
now; only `.js` and `.ts` fall back to content.
- The Nuxt flat-config template inlines the projectService block
directly because the generated `createConfigForNuxt(...).append(...)`
chain is a call expression, not an array literal that AST helpers can
append to.
- `@nx/cypress` and `@nx/playwright` added as optional peer dependencies
of `@nx/angular`, `@nx/expo` and `@nx/nuxt` so cross-plugin `typeof
import('@nx/cypress' | '@nx/playwright')` resolves to local source.
Angular's existing `@nx/cypress` declaration moves from
`devDependencies` to optional peer for consistency.
- `@nx/js` cannot reference `@nx/eslint` (eslint depends on js), so the
merge is inlined there.
- The typed-linting guide (`astro-docs/.../eslint.mdoc`) taught the
flat-config tab to fix a type-aware rule by adding
`parserOptions.project`, which now conflicts with what the generators
emit. Its flat tab teaches the project service instead, and
`enableTypedLinting` is documented.
- `--setParserOptionsProject=true` on a flat-config workspace now
produces a different output shape than before: the projectService block
rather than `parserOptions.project`. Intended, and covered by tests, but
it is a behavior change to an existing flag.
- No migration: existing generated `parserOptions.project` configs are
left untouched.
- `convert-to-flat-config` preserves the legacy shape during conversion.
> [!NOTE]
> Reviewing this PR surfaced pre-existing defects in how the ESLint
generators resolve a project's config file when its format differs from
the workspace's. They reproduce on master, are not introduced or made
worse by this change, and are being addressed in separate follow-up PRs.
<!-- polygraph-session-start -->
---
[View session information
↗](https://snapshot.app.trypolygraph.com/orgs/69cdc268b6aa527e4129c2b4/sessions/nxc-4473-e27e6e99)
<!-- polygraph-session-end -->
---------
Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
|
||
|
|
5bda3c76d8 |
chore(testing): make node/express app generator specs package-manager-agnostic (#36369)
## Current Behavior The `@nx/node` and `@nx/express` application generator specs snapshot values that are derived from the **host** package manager, so running them under a different package manager than CI (e.g. pnpm locally vs. npm in CI) produces spurious snapshot churn: - The **lock file name** in `prune-lockfile` outputs (`package-lock.json` vs. `pnpm-lock.yaml`) — from `getPruneTargets`, which calls `detectPackageManager()`. - The **`runtimeExecutable`** in the generated VS Code debug config — from `getPackageManagerCommand()`. `detectPackageManager()` checks the cwd's lock files before the invoked-package-manager fallback, and the nx repo root has a `pnpm-lock.yaml`, so these specs detect pnpm locally regardless of `npm_config_user_agent`. A contributor who runs the tests under pnpm and regenerates snapshots ends up committing pnpm-specific values that then fail on npm CI. ## Expected Behavior The specs are deterministic regardless of which package manager runs them. Both specs mock `@nx/devkit` to pin `detectPackageManager` to `'npm'` and delegate `getPackageManagerCommand` to the real npm command (mirroring the existing mock in the `@nx/react` application spec). Because the committed snapshots are already the npm result, this introduces **no** snapshot changes — only immunity to the host package manager. `detectPackageManager()`'s production behavior is unchanged (in a real workspace the cwd is the workspace root); this is purely test determinism, so there is no source change. ## Related Issue(s) N/A — proactive test hardening. Surfaced while reviewing #35551, whose generator snapshot churn was caused by this host-package-manager sensitivity. <!-- polygraph-session-start --> --- [View session information ↗](https://app.trypolygraph.com/orgs/6a061dcb561c062131116eca/sessions/Make-node-express-app-generator-specs-package-manager-agnostic-a382908b) <!-- polygraph-session-end --> |
||
|
|
a88e49473f |
chore(repo): migrate to nx 23.1.0-rc.2 (#36269)
## Current Behavior The repo is on nx 23.1.0-beta.7. ## Expected Behavior The repo is on nx 23.1.0-rc.2. All 22 `nx`/`@nx/*` packages are bumped to exactly 23.1.0-rc.0 (pnpm lockfile updated). Migrations applied (one `nx migrate --run-migrations` pass): - `@nx/js: 23-1-0-add-ignore-deprecations-for-ts6` — ensured `"ignoreDeprecations": "6.0"` on 125 `tsconfig.json` files (config-loader safety for TS6), added it to 2 tsconfigs carrying TS6-deprecated options, and pinned pre-TS6 defaults on 4 chain-root tsconfigs - `@nx/js: 23-1-0-set-tsconfig-root-dir-for-ts6` — ran, no changes needed No AI migration prompts were generated. Verification: project graph resolves (~140 projects); lint for nx, devkit, js, eslint, workspace (+23 dependent tasks, including the native build) and typecheck spot-checks pass with `--skip-nx-cache`. Full suite runs in CI. ## Related Issue(s) Part of the coordinated nx 23.1.0-rc.2 migration across nrwl repos (see linked Polygraph session). <!-- polygraph-session-start --> --- [View session information ↗](https://app.trypolygraph.com/orgs/6a061dcb561c062131116eca/sessions/Migrate-nrwl-repos-to-nx-23.1.0-rc.0-b8c94700) <!-- polygraph-session-end --> --------- Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com> |
||
|
|
f22e75c8f0 |
feat(repo): enable the tsgo compiler workspace-wide (#35926)
## Current Behavior The workspace builds and typechecks every first-party package with `tsc`. An earlier attempt to enable the Go-based TypeScript compiler (tsgo) for just `packages/nx` (#35047) was reverted (#35167) because mixing compilers caused `.tsbuildinfo` version-mismatch cascades — a downstream `tsc --build` would see a tsgo-stamped build info and recompile everything. ## Expected Behavior The entire `@nx/js/typescript` build + typecheck graph — packages, graph, tools, `e2e/**`, and `nx-dev/ui-fence` — compiles with `tsgo`. Now that every package is on `nodenext` (NXC-4538), a single compiler runs across the whole graph, so there is no cross-compiler `.tsbuildinfo` cascade. ### Changes - Install `@typescript/native-preview` and set `compiler: "tsgo"` on **both** `@nx/js/typescript` plugin entries (the package build/typecheck entry and the e2e/nx-dev typecheck entry — the latter does `tsc --build` with references into `packages/*`, so it had to move too). - `tsconfig.base.json`: switch to `nodenext` module resolution, remove `baseUrl` (tsgo removed it — `TS5102`), and set `strict: false` to preserve current tsc behavior (tsgo defaults strict on). - Align spec/e2e tsconfig `module` to `nodenext` (`TS5110`) and add `customConditions: ["@nx/nx-source"]` to the spec tsconfigs so test files resolve `@nx/*` subpaths to workspace **source** — notably `@nx/devkit/internal-testing-utils`, which is excluded from devkit's build so no declaration is emitted under nodenext. - Source fixes surfaced by tsgo: two accidental workspace-root (`baseUrl`-anchored) imports now use package names; `@nx/expo` `addJest` gets an explicit `Promise<GeneratorCallback>` return type; `@nx/angular` webpack-browser casts past the angular/webpack plugin type difference; `graph/client-e2e` cypress global augmentations and `AUTWindow` casts; `Task` mocks get the required `cache` field; `update-repos`/`create-embeddings` config fixes. ## Validation - `build-base`: **42 projects green** under tsgo. - `typecheck`: **53 projects, 0 errors** under tsgo (entire `@nx/js/typescript` graph). - lint / test / e2e: pending CI. > Note: tsgo's incremental/cached builds occasionally drop emitted declarations (observed with devkit's `internal-testing-utils`); a from-scratch build emits them. Worth watching in CI. The remaining `tsc` users — `astro-docs` (astro check), `nx-dev`'s Next.js build, and `@nx/angular`'s ng-packagr (ngc) — do **not** `tsc --build` the packages, so they don't share `.tsbuildinfo` with the tsgo graph and coexist safely. ## Related Issue(s) Implements Linear NXC-4539 (builds on NXC-4538 — all packages on nodenext). No GitHub issue to close. --------- Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com> |
||
|
|
192f66811d |
feat(angular): support angular v22 (#35851)
## Current behavior Angular v22 is not supported. ## Expected behavior Angular v22 should be supported. BREAKING CHANGE: Angular v19 is no longer supported. ## Related issues Fixes #35910 <!-- polygraph-session-start --> --- [View session information ↗](https://app.trypolygraph.com/orgs/6a061dcb561c062131116eca/sessions/angular-v22-3d830e58) <!-- polygraph-session-end --> --------- Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com> |
||
|
|
a44086e45f |
feat(linter)!: drop eslint v8 support (#36006)
## Current Behavior Nx supported both ESLint v8 and v9. The `@nx/eslint` runtime, generators, executors, and inferred plugin carried v8-specific branches, version floors allowed v8-only ranges, and `useFlatConfig` chose flat vs eslintrc purely by the installed ESLint version - which could select flat config on an eslintrc workspace and crash generators. ## Expected Behavior ESLint v8 support is removed and Nx targets ESLint v9+. Flat config is the default for new workspaces, while existing eslintrc workspaces stay supported: `useFlatConfig` now respects a root flat/eslintrc config file and the `ESLINT_USE_FLAT_CONFIG` env var. Version floors, the lockfile, and docs move to v9+. Generator specs across the linting-capable plugins assert flat config by default and each retains at least one eslintrc test. BREAKING CHANGE: ESLint v8 is no longer supported. Nx requires ESLint v9 or later. <!-- polygraph-session-start --> --- [View session information ↗](https://app.trypolygraph.com/orgs/6a061dcb561c062131116eca/sessions/drop-eslint-v8-ad08cc1c) <!-- polygraph-session-end --> --------- Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com> Co-authored-by: leosvelperez <leosvelperez@users.noreply.github.com> |
||
|
|
6598a0bb29 |
chore(core): rename supportsOptionalUpdates to supportsOptionalMigrations (#35924)
## Current Behavior The migration config flag that opts a package into `nx migrate --include` (optional migrations) is named `supportsOptionalUpdates`. It is read from a package's `nx-migrations` / `ng-update` config and threaded through the migrate command. The name says "updates", but the feature it gates is optional **migrations**, so the name is misleading. ## Expected Behavior The flag is renamed to `supportsOptionalMigrations` everywhere it is defined and consumed: - The `NxMigrationsConfiguration` / `NxPackageJson` type field and the `readNxMigrateConfig` parsing in `packages/nx/src/utils/package-json.ts` - The `--include` gate and related plumbing in `packages/nx/src/command-line/migrate/migrate.ts` - The `"supportsOptionalMigrations": true` flag in every first-party plugin's `package.json` - The associated unit tests This is a purely internal rename — the flag is both defined and consumed inside the nx repo, so no backwards-compat shim is required. Behavior is unchanged. ## Related Issue(s) N/A — internal naming cleanup. --------- Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com> |
||
|
|
27f9ae0a37 |
chore(repo): finish migrating builds off the workspace-root dist (#35915)
## Current Behavior Following the local-dist migration (#35900), several projects were still writing build or typecheck output to the shared workspace-root `dist/`: - **Five packages' spec configs** — `@nx/angular-rspack`, `@nx/angular-rspack-compiler`, `@nx/dotnet`, `@nx/maven`, and `nx` — kept their `tsconfig.spec.json` `outDir` pointing at `dist/packages/<name>/spec` even though their lib output had been migrated to a local `dist`. - **`tools/workspace-plugin`** built to the shared `dist/workspace-plugin` (its conformance rules are loaded from the built output). - **The graph client** bundled to `dist/apps/graph` and emitted its typecheck declarations to `dist/graph/client`; the graph libs wrote spec/storybook typecheck output under `dist/out-tsc`. - **nx-dev** lib/spec tsconfigs pointed their `outDir` at `dist/out-tsc/...`. Separately, astro-docs documentation generation resolved each plugin's `schema.json` from its **built** `dist` (the migrated `generators.json`/`executors.json` refs point at `./dist/src/...`). Reading another project's build output tripped the task sandbox with undeclared `dist/**/schema.json` reads. ## Expected Behavior Each project builds to its own local directory, leaving the workspace-root `dist/` alone: - The five spec configs now emit to local `dist/spec`. - `tools/workspace-plugin` builds to `tools/workspace-plugin/dist`; the seven conformance rule paths in `nx.json` are updated, and `main`/`typings` are repointed into `dist` so the `@nx/js/typescript` plugin still infers its build target. - The graph client bundles to `graph/client/dist` (the `nx` package's `assets.json` input is updated to match); its typecheck output goes to a local `out-tsc` so the emitted declarations stay out of the copied bundle dir. Graph lib spec/storybook output moves to local `dist`. - nx-dev lib/spec outputs move to local `dist` / `dist/spec` (preventative — these were vestigial as no target runs `tsc` on most nx-dev libs today). astro-docs now reads plugin `schema.json` from source (the verbatim copy), which also matches `astro-docs:build`'s already-declared `packages/*/src/.../schema.json` inputs — removing the sandbox violation without weakening cache correctness. Validation: `nx build workspace-plugin` + `nx conformance` pass from the new path; the graph client builds and copies into `packages/nx/dist/src/core/graph` with no declaration leakage; `nx build astro-docs` is green (753 pages, no schema-resolution errors); affected graph and nx-dev `typecheck`/`lint`/`test` pass. ## Related Issue(s) Follow-up to #35900 (local-dist build migration). No separate issue. --------- Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com> |
||
|
|
8039b7bae3 |
feat(misc): remove migrations prior to v21 in preparation for v23 (#35909)
## Current Behavior The first-party Nx plugins still ship migration code (and `packageJsonUpdates`) targeting Nx **v20 and earlier**. With v23 on the way, those migrations are dead weight in the published packages and their `migrations.json` manifests. ## Expected Behavior All migrations prior to **v21** are removed across the first-party plugins via the `@nx/workspace-plugin:remove-migrations` generator (`--v=21`), keeping the two most recent prior majors (v21, v22) plus v23 — consistent with prior major-release prep (#30839 removed `< v19`, #32904 removed `< v20`). `packages/nx` and `packages/angular` are intentionally preserved (`nx` is needed for `nx repair`; `angular` keeps its migrations until LTS support is dropped). Because the recent move to local dist builds (#35900) means every plugin's `migrations.json` now references built (`./dist/...`) paths, the generator can no longer auto-delete the corresponding source files. The orphaned pre-v21 migration source directories were removed manually as part of this change. ## Related Issue(s) N/A — release preparation for v23. --------- Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com> Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com> |
||
|
|
38ca20b45e |
feat(core): extend nx migrate --include to any package that supports optional updates (#35905)
## Current Behavior `nx migrate --include` only applies when migrating Nx itself; for any other target the option is rejected, and eligibility is derived from Nx-specific version math. ## Expected Behavior `--include` now applies to any package whose `nx-migrations` / `ng-update` config declares `supportsOptionalUpdates: true`, read from the package metadata via the shared fetcher (registry-first, install fallback). It accepts `required` (the target package and the related packages it ships with), `optional` (the optional dependency updates those packages recommend), or `all` (default). The `--interactive` / `x-prompt` confirmation flow is deprecated in favor of `--include` (removal slated for Nx v24; no hard error yet), and `supportsOptionalUpdates: true` is set on the first-party packages. <!-- polygraph-session-start --> --- [View session information ↗](https://snapshot.app.trypolygraph.com/orgs/69cdc268b6aa527e4129c2b4/sessions/nxc-4517-37fe1336) <!-- polygraph-session-end --> |
||
|
|
4bb6115625 |
chore(repo)!: migrate remaining packages to local dist build (#35900)
## Current Behavior
The remaining 14 publishable packages still build to the shared
workspace output `dist/packages/<name>` and use `commonjs`/`node` module
resolution. This is the last set of packages on the old layout — `nx`,
`devkit`, `js`, `web`, `node`, `webpack`, etc. were already migrated.
## Expected Behavior
Each of the remaining packages now builds to its own local
`packages/<name>/dist` directory with `nodenext` module resolution and
an `exports` map using the custom `@nx/nx-source` condition (so
in-workspace consumers resolve to source, while published/runtime
consumers resolve to built `./dist`). This matches the already-migrated
packages.
Packages migrated (one commit each):
- **Tier 0:** `@nx/react`, `@nx/esbuild`, `@nx/express`, `@nx/vue`,
`@nx/plugin`, `create-nx-workspace`, `@nx/angular`
- **Tier 1:** `@nx/react-native`, `@nx/next`, `@nx/remix`, `@nx/detox`,
`@nx/expo`, `@nx/nuxt`, `create-nx-plugin`
Notes:
- Kept the `./src/*` wildcard exports (the `@nx/nest` pattern) so no
consumer imports needed editing; the optional `./internal` lockdown is
deferred to a follow-up.
- Converted `ensurePackage` + `await import('@nx/...')` pairs to typed
`require()` (ESM dynamic import ignores `Module._initPaths` under
`nodenext`) and replaced `require('../../package.json')` self-references
with the dynamic `require(join('@nx/<name>', 'package.json'))` form.
- `@nx/angular` keeps its dual build: `tsc` (`build-base`) + ng-packagr
(`build-ng`); `ng-package.json` `dest`, both tsconfig `outDir`s, and the
publish `packageRoot` were relocated to `packages/angular/dist`.
- `create-nx-workspace`/`create-nx-plugin` were missing from the
migration board; tracked as NXC-4515 / NXC-4516.
Validation: `nx run-many -t build,lint` is green across all 14 packages
(including angular's real ng-packagr build and
`@nx/nx-plugin-checks`/`@nx/dependency-checks`). **Still needs CI
validation:** full e2e and the `nx release`/publish path (notably
angular's ng-packagr `packageRoot`).
## Breaking Changes
This is a breaking change because only `/internal` can be imported on packages now rather than importing from `src`. There is a migration to take care of this when necessary though.
## Related Issue(s)
Linear: NXC-3580, NXC-3582, NXC-3583, NXC-3584, NXC-3585, NXC-3587,
NXC-3589, NXC-3590, NXC-3596, NXC-3597, NXC-3600, NXC-3601, NXC-4515,
NXC-4516
---------
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
|
||
|
|
3a33712668 |
fix(repo)!: migrate remaining first-party plugins to local dist build (M2-M5) (#35785)
## Current Behavior The remaining 11 first-party Nx plugins (`@nx/webpack`, `@nx/rollup`, `@nx/docker`, `@nx/gradle`, `@nx/rsbuild`, `@nx/web`, `@nx/node`, `@nx/nest`, `@nx/module-federation`, `@nx/rspack`, `@nx/storybook`) build into `../../dist/packages/<name>/` with `module: commonjs` and no `exports` map. Releases publish from a separate dist directory. That layout has the same drawbacks the prior migrations (devkit, workspace, nx, js, jest, eslint, eslint-plugin, vitest, cypress, playwright, vite) already addressed: - workspace consumers reach into `@nx/<name>/src/*` against the old layout, blocking nodenext / ESM-friendlier resolution - a single PR cannot publish a coordinated set because each package's dist must round-trip through `nx release` - `release.preserveLocalDependencyProtocols` cannot be turned on workspace-wide This PR is the final batch in the "Nx Local Dist Migration" project — it unblocks every still-unmigrated workspace package and finishes the rollout that started with `@nx/devkit` in #34946. ## Expected Behavior All 11 packages build to `packages/<name>/dist/` with: - `tsconfig.lib.json` set to `module: nodenext`, `moduleResolution: nodenext`, `composite: true`, `outDir: dist`, `declarationDir: dist`, `tsBuildInfoFile: dist/tsconfig.tsbuildinfo` - `package.json` `main`/`types` pointing into `dist/`, an `exports` map with `@nx/nx-source`/`types`/`default` conditions, `typesVersions` for legacy `moduleResolution: node` consumers, and a `files` allowlist - `project.json` `release.version.preserveLocalDependencyProtocols: true`, `manifestRootsToUpdate: ["packages/{projectName}"]`, and `nx-release-publish.packageRoot: packages/{projectName}` - `assets.json` `outDir` and eslint `dist` ignore updated - `src/utils/versions.ts` switched to `require(join('@nx/<name>', 'package.json')).version` so the self-reference survives the new layout - `README.md` renamed to `readme-template.md` with the build's `copy-readme.js` invocation passing explicit src/dest paths, and root `.gitignore` updated for the generated `README.md` - `scripts/nx-release.ts` `packagesToReset` extended so `nx release` properly snapshots/restores these source `package.json`s The 11 packages keep the `./src/*` wildcard in their exports map for now — the `@nx/devkit/internal`-style lockdown (Step 14b of the `dist-build-migration` skill) is intentionally deferred to per-package follow-up PRs to keep this one focused on the layout move. Two runtime fixes that mirror earlier work in this project: - `@nx/node` now declares `@nx/webpack` as a `workspace:*` devDep so its TS compile resolves `@nx/webpack/src/utils/ensure-dependencies` via the new exports map; the dynamic `import()` of that subpath was swapped to `require()` after `ensurePackage` so the temp install is visible (same pattern as the vite/vitest fix in #35743 — under `module: nodenext` a dynamic `import()` is preserved as a true ESM import and bypasses `Module._initPaths`). - `@nx/web` had two dynamic `await import('@nx/eslint/internal')` / `await import('@nx/vitest/generators')` call sites; both swapped to `require()` with `typeof import(...)` type annotations for the same reason. `e2e/nx-build/src/nx-build.test.ts` was extended to verify the new output paths for all 11 packages. ## Related Issue(s) Fixes NXC-3576 Fixes NXC-3577 Fixes NXC-3579 Fixes NXC-3586 Fixes NXC-3588 Fixes NXC-3591 Fixes NXC-3595 Fixes NXC-3598 Fixes NXC-3599 Fixes NXC-3602 Fixes NXC-4474 --------- Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com> |
||
|
|
193b8fce0b |
fix(misc): multi-version support compliance for rollup, webpack, and module-federation (#35860)
## Current Behavior `@nx/rollup`, `@nx/webpack`, and `@nx/module-federation` pin their primary third-party packages as **bundled `dependencies`**: - `@nx/rollup` → `rollup` (`^4.14.0`) - `@nx/webpack` → `webpack`, `webpack-dev-server` (v5) - `@nx/module-federation` → `@module-federation/enhanced`, `@module-federation/node`, `@module-federation/sdk` (v2) This causes version conflicts with the version a workspace actually has installed, prevents `nx migrate --first-party-only` from upgrading Nx without dragging these along, and lets generators silently overwrite a user's pinned version. Several cross-version `packageJsonUpdates` migrations also bump packages **without `requires` gates**, so they fire on workspaces outside the intended source range (e.g. the `@nx/webpack` `sass-loader` v12 → v16 bump, and all of `@nx/module-federation`'s `@module-federation/*` bumps). ## Expected Behavior Each plugin declares the packages it invokes at runtime as **optional peer dependencies** matching its real support window, so the workspace controls the version: - `@nx/rollup` → `rollup` `^3.0.0 || ^4.0.0` - `@nx/webpack` → `webpack` / `webpack-dev-server` / `webpack-cli` `^5.0.0` (the effective floor — the plugin already calls webpack-5-only APIs such as `ids.HashedModuleIdsPlugin`, `webpack.sources`, and `experiments.cacheUnaffected`) - `@nx/module-federation` → `@module-federation/enhanced` / `@module-federation/node` `^2.0.0` (`@module-federation/sdk` stays a dependency — it is a type-only import surfaced in the public `.d.ts`) Generators assert the supported floor (with a parameterized `all-generators-enforce-floor` spec), preserve user-pinned versions (`keepExistingVersions` now defaults to `true`), and install the now-peer build tool for new workspaces. Because every workspace that uses these tools already has the corresponding `@nx/*` plugin as a direct dependency, a `packageJsonUpdates` bridge in each plugin installs the peer into existing workspaces on `nx migrate` (and correctly skips workspaces that only carry the plugin transitively). Cross-version migrations are gated on their source range. ### Changes per plugin - **`@nx/rollup` (NXC-4403)** — `rollup` → optional peer; floor assert (v3) in all generators; `keepExistingVersions` default `true`; install `rollup` on both the inferred-plugin and executor paths; bridge migration for existing workspaces. No runtime branching/version map is needed — the plugin's Rollup usage is already v2/v3/v4-agnostic. - **`@nx/webpack` (NXC-4410)** — `webpack`/`webpack-dev-server`/`webpack-cli` → optional peers (`^5`); floor assert (v5) in all generators; `keepExistingVersions` default `true`; gate the `sass-loader` v12 → v16 migration on `^12`; install `webpack`/`webpack-dev-server` for new workspaces; bridge migration for existing ones. - **`@nx/module-federation` (NXC-4393)** — `@module-federation/enhanced`/`node` → optional peers (`^2`); add `requires` gates (on the `@module-federation/enhanced` source range, mirroring the existing `@nx/angular` MF migrations) to every `packageJsonUpdates` entry, and split the independent `http-proxy-middleware` v2 → v3 bump into its own gated entry. This is a runtime-only library (no generators/executors), so there is no floor assert/spec. ## Related Issue(s) Tracked in Linear under the "Multi-version supported across plugins" milestone: - NXC-4403 — `@nx/rollup` - NXC-4410 — `@nx/webpack` - NXC-4393 — `@nx/module-federation` No GitHub issue to auto-close. --------- Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com> |
||
|
|
2ded1d14b2 |
feat(devkit)!: deprecate the standalone parameter of addProjectConfiguration (#35883)
## Current Behavior `addProjectConfiguration` exposes a 4th `standalone` parameter (defaulting to `true`). Nx only supports standalone projects, so any value other than `true` is ignored — passing `standalone: false` simply prints a warning and otherwise has no effect. Despite being a no-op, the parameter is still part of the public signature, and a number of first-party generators expose a matching `standaloneConfig` schema option whose only job is to feed this dead parameter. ## Expected Behavior `addProjectConfiguration` now presents two TypeScript overloads: - a clean 3-argument signature (`tree`, `projectName`, `projectConfiguration`), and - a `@deprecated` 4-argument signature that still accepts `standalone` for backwards compatibility (the runtime behavior is unchanged — it continues to warn when set to `false`). Existing callers keep compiling, but new ones are steered onto the 3-argument form and editors surface a deprecation strikethrough on the old one. The vestigial `standaloneConfig` option has been removed from the affected generator schemas (`schema.json` + `schema.d.ts`) across `expo`, `node` (application + library), `nest`, `storybook`, `workspace` preset, `plugin`, and `express`, since it only ever populated the ignored parameter. The remaining internal 4-argument call sites (`expo`, `node`, and the `angular` ng-add e2e migrator) were reduced to the 3-argument overload, the `nest`/`workspace` passthroughs were cleaned up, and the storybook generator specs no longer pass `standaloneConfig`. Verified locally: `lint` passes for the 9 touched projects, `build` (typecheck) passes for `nx`, `node`, `expo`, `nest`, and `workspace`, and the storybook `configuration` spec passes. ## Related Issue(s) N/A --------- Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com> |
||
|
|
412a37a16c |
fix(misc): multi-version compliance for @nx/express, @nx/node, and @nx/nest (#35807)
## Current Behavior
**`@nx/express`**
- Peer dep declares `express: ^4.21.2` only; Express v5 has been ACTIVE
since 2025-03-31 and v4 is in MAINT, so the plugin's advertised window
doesn't match the upstream support window.
- Generators install a single literal `express ^4.21.2` regardless of
what's installed; no per-major routing for `express` or
`@types/express`.
- `keepExistingVersions` schema default is `false`, so re-running the
generator silently overwrites a user's pinned `express` version.
- No floor enforcement: a workspace on an unsupported (sub-floor)
`express` version sees no error.
**`@nx/node`**
- No `peerDependencies` for `express`, `koa`, or `fastify`.
Init/application generators write framework deps unconditionally,
ignoring what's installed.
- `keepExistingVersions` defaults to `false`; framework installs
override user pins.
- `migrations.json` `22.0.2` bumps `koa` from v2 to v3 with no
`requires` block — every workspace on koa v2 gets pushed to v3
unconditionally.
- `migrations.json` `20.4.0` mixes a cross-major fastify v4→v5 bump with
same-major express bumps under one entry, with no `requires`
(AND-semantics would gate same-major bumps incorrectly if added
naively).
- No floor enforcement for any framework.
**`@nx/nest`**
- `peerDependencies` block is missing from `package.json` entirely;
workspaces have no advertised compatible range for any `@nestjs/*`
package.
- Versions module has flat constants; the plugin ships v11-only even
though NestJS v10.4.x still receives upstream patches (N & N-1 baseline
calls for v10 + v11).
- `migrations.json` `21.2.0-beta.2` uses a bare key `nest` which is not
a real npm package — the entry is effectively a no-op. The real
cross-major v10→v11 bump for `@nestjs/common`, `@nestjs/core`,
`@nestjs/platform-express`, `@nestjs/testing` is missing, as is a
`requires` source-major gate.
- No floor enforcement for any NestJS version.
## Expected Behavior
**`@nx/express` (NXC-4390)**
- Per-major `versionMap` keyed on `express` major covering both
`express` and `@types/express` for v4 and v5; fresh installs default to
v5.1.0.
- `assertSupportedExpressVersion(tree)` (calls shared
`assertSupportedPackageVersion`) is the first statement of
`initGenerator` and `applicationGeneratorInternal`.
- Peer widened to `express: ">=4.0.0 <6.0.0"` (still optional).
- All `addDependenciesToPackageJson` call sites from generators pass
`keepExistingVersions ?? true`; schema defaults flipped to `true`. Init
now installs `@types/express` (previously a dead export).
- New `all-generators-enforce-floor.spec.ts` exercises every generator
entry at `subFloorVersion: '~3.21.0'`.
- Supported-versions docs page updated.
**`@nx/node` (NXC-4396)**
- Per-package `versionMap` + `versions(tree)` for `express` (v4+v5),
`koa` (v2+v3), `fastify` (v4+v5), and `@types/node` (v22+v24). Fresh
installs default to active LTS / latest stable.
- `assertSupportedFrameworkVersion(tree, schema.framework)` (dispatches
to one wrapper per framework) is the first statement of
`applicationGeneratorInternal`, only firing when `--framework` selects a
non-`none`/`nest` lane.
- Framework + `@types/node` installs route through `versions(tree)` and
pass `keepExistingVersions ?? true`. Init schema default flipped to
`true`.
- `migrations.json`: `22.0.2` koa v2→v3 gated with `requires: { koa:
">=2.0.0 <3.0.0" }`. `22.6.0` koa CVE patch gated bilaterally to v3
only. `20.4.0` split into the original same-major express bumps (no
gate) and a new `20.4.0-fastify` entry gated on `requires: { fastify:
">=4.0.0 <5.0.0" }`.
- Optional `peerDependencies` declared for `express`, `koa`, `fastify`.
Added `semver: "catalog:"` to deps (now imported by `versions.ts`).
`@nx/dependency-checks` allow-list updated.
**`@nx/nest` (NXC-4394)**
- Per-major `versionMap` covering NestJS v10 and v11 for the full
`@nestjs/*` family plus `rxjs` and `reflect-metadata`. Fresh installs
default to NestJS v11, with `reflect-metadata` bumped from `^0.1.13` to
`^0.2.0` to match v11's requirement.
- `assertSupportedNestJsVersion(tree)` is the first statement of the
`init`, `application`, and `library` generators.
- `ensureDependencies` and the init `addDependencies` helper route
through `versions(tree)` and pass `keepExistingVersions: true` (`??
true` on the init path); init schema default flipped to `true`.
- Optional `peerDependencies` declared for `@nestjs/core`,
`@nestjs/common`, `reflect-metadata`, `rxjs`. Added `semver: "catalog:"`
to deps and extended `@nx/dependency-checks` allow-list.
- `migrations.json` `21.2.0-beta.2` rewritten with real package keys
(the previous bare `nest` key was a typo / no-op) and gated on
`requires: { "@nestjs/core": ">=10.0.0 <11.0.0" }`. The entry now also
bumps `reflect-metadata` to `^0.2.0` for v11 compatibility.
- Supported-versions docs page updated.
## Related Issue(s)
Fixes NXC-4390
Fixes NXC-4396
Fixes NXC-4394
---------
Co-authored-by: Craigory Coppola <craigorycoppola@gmail.com>
|
||
|
|
67d3502adc |
fix(linter)!: migrate @nx/eslint and @nx/eslint-plugin to local dist build (#35720)
## Current Behavior
`@nx/eslint` and `@nx/eslint-plugin` build into the shared
`dist/packages/<name>` directory at the workspace root. `@nx/eslint`
exposes no `exports` map, so first-party packages reach into
`@nx/eslint/src/*` for internal utilities.
## Expected Behavior
Both packages build locally into `packages/<name>/dist/` with `nodenext`
module resolution and an `exports` map, matching the already-migrated
`nx`, `devkit`, `js`, and `jest`.
### `@nx/eslint`
- `tsconfig.lib.json` / `tsconfig.spec.json` switched to the nodenext +
local-`dist` pattern.
- `package.json` gains an `exports` map (`.`, `./plugin`, `./internal`,
plus the JSON configs), `typesVersions`, and a `files` field.
- `project.json` gains `release` and `nx-release-publish` configuration.
- `executors.json` / `generators.json` / `migrations.json` paths
repointed to `./dist/src/...`.
- `src/utils/versions.ts` resolves its own `package.json` via a
`@nx/eslint` self-reference.
- **Exports lockdown:** the broad `src/*` surface is dropped; a curated
`@nx/eslint/internal` entry replaces it. 27 first-party consumer files
are rewritten from `@nx/eslint/src/*` to `@nx/eslint/internal`, and a
`rewrite-eslint-internal-subpath-imports` migration rewrites user
imports (symbol-aware — public symbols → `@nx/eslint`, internals →
`@nx/eslint/internal`).
- `@nx/vite` and `@nx/remix` imported `@nx/eslint` utilities without
declaring the dependency; `@nx/eslint` is now a declared dependency of
both.
### `@nx/eslint-plugin`
- Same nodenext + local-`dist` migration.
- `package.json` `exports` map covers `.`, `./angular`, `./nx`,
`./react`, `./typescript`. No `./internal` entry — nothing imports its
`src/*`.
## Related Issue(s)
Tracked by Linear NXC-3575 (`@nx/eslint`) and NXC-4475
(`@nx/eslint-plugin`). No GitHub issue.
<details>
<summary>Notes</summary>
- `@nx/js` and `@nx/workspace` also call `@nx/eslint` utilities but
cannot declare the dependency — `@nx/eslint` depends on `@nx/js`, so
declaring it back would create a cycle. They use a runtime
`require('@nx/eslint/internal')` (no static import), which `tsc` does
not resolve, so their builds are unaffected.
- Validation: `nx affected -t build,lint` is green (only the
pre-existing `MsbuildAnalyzer` dotnet build fails). Affected `:test`
failures are pre-existing environment/snapshot drift — `devkit:test` and
`nx:test` fail identically with zero dependency on these packages, and
`web`/`react` test failure counts match `master` exactly. The
`@nx/eslint`/`@nx/eslint-plugin` suites pass apart from the pre-existing
`workspace-rules-project.spec.ts` "TS solution setup" failure (also
fails on `master`).
</details>
---------
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
|
||
|
|
0f298759a3 |
fix(testing)!: migrate @nx/jest to local dist build (#35713)
## Current Behavior
`@nx/jest` builds into the shared `dist/packages/jest` directory at the
workspace root and compiles with `commonjs` module resolution. It
exposes no `exports` map, and first-party packages (`@nx/detox`,
`@nx/node`) reach into `@nx/jest/src/*` for internal utilities. It also
still re-exports the long-deprecated `jestProjectGenerator` alias.
## Expected Behavior
`@nx/jest` builds locally into `packages/jest/dist/` with `nodenext`
module resolution and an `exports` map, matching the already-migrated
`nx`, `devkit`, and `js` packages.
- `tsconfig.lib.json` / `tsconfig.spec.json` switched to the nodenext +
local-`dist` pattern.
- `package.json` gains an `exports` map (`.`, `./plugin`, `./preset`,
`./plugins/resolver`, `./internal`, plus the JSON configs),
`typesVersions`, and a `files` field.
- `project.json` gains `release` (`preserveLocalDependencyProtocols`,
`manifestRootsToUpdate`) and `nx-release-publish` configuration.
- `executors.json` / `generators.json` / `migrations.json` factory and
schema paths repointed to `./dist/src/...`.
- `assets.json` outputs to the local `dist/` and copies
`src/**/schema.json`.
- `src/utils/versions.ts` resolves its own `package.json` via a
`@nx/jest` self-reference instead of a `../../` relative path, which
breaks once source compiles into `dist/`.
- The `@nx/jest:jest` executor imports its `schema.json` statically
rather than via a dynamic `await import`.
- A curated `@nx/jest/internal` entry (mirroring `@nx/devkit/internal`)
replaces deep `@nx/jest/src/*` imports for first-party consumers;
`@nx/detox` and `@nx/node` are routed through it.
- A migration (`rewrite-jest-internal-subpath-imports`) rewrites user
`@nx/jest/src/*` imports: named imports/exports of public symbols go to
`@nx/jest`, everything else to `@nx/jest/internal`.
- A migration (`rewrite-jest-project-generator`) rewrites
`jestProjectGenerator` imported from `@nx/jest` to
`configurationGenerator`.
The `dist-build-migration` skill is also updated to document the
symbol-aware routing rule for the migration step.
### Breaking Changes
- The deprecated `jestProjectGenerator` export is removed — its "removed
in Nx v22" notice is two majors overdue. It was always just an alias for
`configurationGenerator`; the `rewrite-jest-project-generator` migration
rewrites existing usages automatically.
## Related Issue(s)
Tracked by Linear NXC-3592 — `[M4] [Epic] Migrate @nx/jest to local
dist`. No GitHub issue.
<details>
<summary>Pre-create review (run before PR open)</summary>
### Critical
- The subpath-import migration originally rewrote every `@nx/jest/src/*`
import to `@nx/jest/internal`, which would silently break consumers
importing a public symbol (e.g. `findJestConfig`) that way. **Fixed** —
the migration now partitions named imports/exports: public symbols route
to `@nx/jest`, internals to `@nx/jest/internal`, splitting mixed
declarations into two.
### Important
- `export { ... } from '@nx/jest/src/*'` and additional `jest`/`vi` mock
helpers were not handled by the initial migration. **Fixed** — export
declarations are now partitioned like imports, and all eight mock-helper
methods are covered with tests.
### Suggestions
- `versions.ts` self-resolve and the inferred `build-base` target were
flagged; both verified correct (matches the `@nx/js` pattern;
`build-base` is inferred by `@nx/js/typescript` from
`tsconfig.lib.json`).
- Softened an over-broad "used only" comment in `eslint.config.mjs`.
</details>
---------
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
|
||
|
|
4f14067546 |
fix(js): build to local dist and use nodenext (#35538)
## Current Behavior `@nx/js` builds to the shared workspace-root `dist/packages/js/` directory, uses CommonJS `module`/`moduleResolution`, has no `exports` map, and relies on `.npmignore`-style filtering through assets.json copies. This makes the package layout diverge from the new pattern already adopted by `nx` and `@nx/devkit`. ## Expected Behavior `@nx/js` follows the same local-dist build pattern as `nx` and `@nx/devkit`: - Builds to `packages/js/dist/` instead of `dist/packages/js/`. - `tsconfig.lib.json` uses `module`/`moduleResolution: "nodenext"` with `composite`, `rootDir: "."`, and `declarationDir: "dist"`. - `package.json` declares an `exports` map with the `@nx/nx-source` condition (workspace consumers resolve to `.ts` source, published consumers get built `.js`), plus a `./src/*` wildcard so the ~296 existing internal imports of `@nx/js/src/...` keep working. - `typesVersions` added for legacy `moduleResolution: "node"` consumers. - Adopts an explicit `files` field on `package.json` instead of asset-copying the root JSONs. - `generators.json`, `executors.json`, `migrations.json` factory/schema paths rewritten `./src/...` → `./dist/src/...` (matches `nx`). Workspace dev still works via the `tryResolveFromSource` fallback in `packages/nx/src/config/schema-utils.ts`. - `README.md` → `readme-template.md`; build command writes the rendered README to `packages/js/README.md`. Root `.gitignore` now ignores `packages/js/README.md` and `packages/js/**/*.d.ts` (with `!packages/js/src/**/schema.d.ts` exception for committed schema declarations). - ESLint flat config ignores `dist` and `**/*.d.ts`. - `project.json` adds `release.version` config (with `preserveLocalDependencyProtocols: false` so the not-yet-migrated `@nx/workspace` dep is substituted to a concrete version at version-time rather than left as `workspace:*` for pnpm publish to resolve from the un-bumped source `packages/workspace/package.json`) and `nx-release-publish.packageRoot`. The `build` target keeps its existing `dependsOn: ["build-base"]` (cannot use `^build` because js's `implicitDependencies` create a cycle through `eslint` / `eslint-plugin`). - `scripts/nx-release.ts`: adds `packages/js` to `packagesToReset` so the source `packages/js/package.json` is restored after release. ## Related Issue(s) Part of the ongoing migration of Nx packages to the local-dist build layout (following `nx` and `@nx/devkit`). --------- Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com> Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com> |
||
|
|
5f534cd5cd |
feat(misc): drop Node 20 support and bump @types/node (#35591)
## Current Behavior CI matrices test Node 20. `@types/node` pinned to v20 in the repo catalog and generator constants. ## Expected Behavior Generator `typesNodeVersion` bumps to `^22.0.0`. Node 20 dropped from e2e + nightly matrices and ESLint docs (EOL Apr 2026). Repo catalog bumps to `^24.11.0` to match `mise.toml`. Nightly `nodeTLS` renamed to `lowestNodeLTS` and bumped to 22. ## Related Issue(s) NXC-4159 |
||
|
|
59e2e51a42 |
chore(devkit): build devkit to local dist and use nodenext (#34946)
## Current Behavior `@nx/devkit` builds to `<workspaceRoot>/dist/packages/devkit/` — outside its own package directory. Other packages reach into that shared workspace `dist/` to consume devkit, and consumers using `moduleResolution: nodenext` need a custom Module._resolveFilename hack to find it. This is inconsistent with `nx` itself, which already builds to `packages/nx/dist/` (#34111). ## Expected Behavior `@nx/devkit` builds to `packages/devkit/dist/` and is consumed via a standard `exports` map. Workspace consumers resolve through normal pnpm symlinks; the `@nx/nx-source` condition still lets in-repo code resolve to `.ts` source during dev. This unblocks the rest of the workspace from migrating in the same direction (a `dist-build-migration` Claude skill is included as a per-package playbook). ## How to review The PR has **307 files but only 3 categories of work**. Most of the diff is mechanical. ### 1. The actual migration — review carefully (~10 files) Devkit package config and the `@nx/nx-source` condition wiring: - `packages/devkit/package.json` — `exports` map, `typesVersions`, `files`, `type: commonjs`, `main`/`types` repointed to `dist/` - `packages/devkit/tsconfig.lib.json` — `outDir: dist`, `nodenext` module/resolution - `packages/devkit/project.json` — `build-base` outputs, `nx-release-publish.packageRoot`, `manifestRootsToUpdate` - `packages/devkit/internal.ts` — re-exports `src/utils/*` and `src/generators/*` symbols (replaces the `@nx/devkit/src/*` deep-import pattern) - `packages/devkit/eslint.config.mjs` — ignore `dist` - `packages/devkit/{README.md → readme-template.md}` — README is now generated, gitignored - `.gitignore` — ignore the generated `packages/devkit/README.md` - `scripts/nx-release.ts` — devkit's `package.json` now lives at `packages/devkit/package.json`, not `dist/packages/devkit/package.json` - `scripts/patched-jest-resolver.js` — adds `@nx/nx-source` condition ### 2. Mass import rewrites — already marked viewed (~205 files) Every internal import of `@nx/devkit/src/utils/<x>` or `@nx/devkit/src/generators/<x>` was rewritten to `@nx/devkit/internal`: ```diff -import { foo } from '@nx/devkit/src/utils/bar'; +import { foo } from '@nx/devkit/internal'; ``` I marked these files as **viewed** in the GitHub review UI to clear them from the unread queue. They're across nearly every plugin (angular, react, next, vite, webpack, rspack, expo, jest, etc.). ### 3. Follow-on cleanups (~10 files) These appear in their own commits and are easy to review individually: - **`cleanup(angular-rspack)`** — removes the `patchDevkitRequestPath` runtime hack from 14 example configs; devkit now resolves through standard node_modules (the MF patch stays — module-federation isn't migrated yet). - **`cleanup(devkit)` typedoc** — drops dead path mappings + redundant include manipulation in `astro-docs/src/plugins/utils/typedoc/typedoc.ts` (verified docs build is byte-identical with/without the removed config). - **`cleanup(devkit)` eslint ignores** — drops `'**/*.d.ts'` from `packages/devkit/eslint.config.mjs` since `.d.ts` files only emit to `dist/` (already ignored). - **`fix(angular)` eslint quote** — quote-agnostic regex in `e2e/angular/src/projects-linting.test.ts` so the test still disables `prefer-standalone` after the angular-eslint generator switched to double quotes (latent bug surfaced by CI). - **`fix(testing)` jest migration** — removes a stray unused `@nx/devkit/internal` import. - **e2e test fallout** — `e2e/{angular,next}/src/*.test.ts` lose access to `@nx/devkit/src/utils/string-utils` (e2e tests can't use `/internal`); inline equivalents using public `names()` API. `e2e/nx-build/src/nx-build.test.ts` updates the expected output path. ## Local verification - `pnpm nx run-many -t test,build,lint -p devkit` ✓ - `pnpm nx run astro-docs:build` ✓ — devkit reference pages still generate (148 markdown files; identical to a build with the path mappings re-added as a control) - `pnpm nx run-many -t build -p examples-angular-rspack-csr-css,examples-angular-rspack-ssr-css,examples-angular-rspack-zoneless-csr-css,examples-angular-rspack-mf-host,examples-angular-rspack-mf-remote --skip-nx-cache` ✓ — examples build without the devkit patch ## Known follow-up (not in this PR) - `scripts/nx-release.ts` still has `hackFixForDevkitPeerDependencies()` (a band-aid from #32406 that re-adds `<=` to devkit's `nx` peer-dep range after `nx release version` strips it). The proper fix is to set `preserveMatchingDependencyRanges: true` in `packages/devkit/project.json` and delete the hack — that needs a release dry-run to verify, so it's queued separately. ## Related Issue(s) Follow-up to #34111. --------- Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com> |
||
|
|
2a412a3aea |
chore(repo): declare lazy-loaded packages as implicit deps (#35392)
## Current Behavior
Many Nx plugin packages lazy-load other plugins at runtime via
`ensurePackage()` or the `require('@nx' + '/...')` pattern. These
dependencies weren't declared in `package.json` at all, which meant:
- `pnpm install` in the monorepo happened to find them only via hoisting
from unrelated `devDependencies`.
- Published packages gave no install-time signal about what optional
peers a consumer might want.
- The dependencies were invisible to dependency-graph tooling,
supply-chain audits, and any future semantic-versioning logic.
## Expected Behavior
Every lazy-loaded plugin or tool is declared as `peerDependencies` +
`peerDependenciesMeta: { X: { optional: true } }`, matching the existing
convention in `@nx/angular`, `@nx/angular-rspack`, `@nx/eslint`, etc.
This gives consumers correct install/publish semantics without requiring
them to install peers they don't use.
For two packages — `@nx/workspace` and `@nx/js` — several of their
newly-declared peers transitively reverse-depend on them. Raw
package.json edges would cause `@nx/js:typescript-sync` to produce
circular TypeScript project references (TS6202). Those two packages use
`implicitDependencies: ["!name", …]` in `project.json` to drop the
cyclic graph edges, keeping the task graph and tsc builds cycle-free
without modifying the sync generator itself.
Commits:
1. **workspace + js**: 14 optional peers on `@nx/workspace`, 5 on
`@nx/js`, plus `implicitDependencies` negations in each `project.json`.
2. **Plugin packages**: `@nx/angular`, `@nx/expo`, `@nx/next`,
`@nx/nuxt`, `@nx/react-native`, `@nx/storybook`, `@nx/vite`, `@nx/vue`,
`@nx/web`. Cycles don't form for any of these, so no
`implicitDependencies` negations were needed. `@nx/js:typescript-sync`
populated the corresponding `tsconfig.lib.json` project references,
which are committed alongside the `package.json` changes.
## Related Issue(s)
Fixes #
## Test plan
see:
https://staging.nx.app/runs/m3Otv2Xl7m?sandboxViolations=true&query=%3Atest
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com>
|
||
|
|
ca7671afd6 |
fix(bundling): include tsconfig solution input for webpack (#35477)
## Current Behavior The `@nx/webpack` executor, inferred plugin, and config builder all call `isUsingTsSolutionSetup()` and let its result influence task outputs (e.g. `useTsconfigPaths`). However, the root `tsconfig.json` is not part of the build task's cache inputs — so edits to root `tsconfig.json` (`extends`, `files`, `include`) don't invalidate webpack task caches and stale outputs are reused. The same gap exists in `@nx/node`'s webpack-bundler branch of the application generator: it calls `addBuildTargetDefaults(tree, '@nx/webpack:webpack')` without the tsconfig input, even though the parallel esbuild branch in the same file already passes `TS_SOLUTION_SETUP_TSCONFIG_INPUT`. ## Expected Behavior Matches the rollup fix in #35476: the root `tsconfig.json` is included as a structured input (`{ json: '{workspaceRoot}/tsconfig.json', fields: ['extends', 'files', 'include'] }`) on `@nx/webpack:webpack` task defaults and in the inferred plugin's build target inputs, so changes to the relevant fields invalidate caches. ### Changes - `packages/webpack/src/plugins/plugin.ts` — append `TS_SOLUTION_SETUP_TSCONFIG_INPUT` to the inferred build target's `inputs`. Also gate the targets cache on `NX_CACHE_PROJECT_GRAPH` (mirrors the rollup PR) and update the spec accordingly. - `packages/webpack/src/generators/configuration/configuration.ts` — pass `'build', [TS_SOLUTION_SETUP_TSCONFIG_INPUT]` to `addBuildTargetDefaults`. - `packages/node/src/generators/application/lib/create-project.ts` — same on the webpack branch (the esbuild branch already had it). - `packages/webpack/src/plugins/plugin.spec.ts` — mock spreads `requireActual` so the constant is real; sets/restores `NX_CACHE_PROJECT_GRAPH`; snapshot updated to include the new input. <!-- polygraph-session-start --> --- [View session information ↗](https://snapshot.app.trypolygraph.com/orgs/69cdc268b6aa527e4129c2b4/sessions/73d1eed2) <!-- polygraph-session-end --> Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com> |
||
|
|
1d6f14dff3 |
fix(node): include tsconfig input in node-app esbuild scaffold (#35466)
## Current Behavior The node app generator with `bundler=esbuild` does not include the field-scoped `tsconfig.json` input needed for proper cache hashing. This means builds may return stale cached results when the workspace's `tsconfig.json` is edited (e.g., changing `extends`, `files`, or `include` fields). ## Expected Behavior The node app generator now includes `TS_SOLUTION_SETUP_TSCONFIG_INPUT` as an input for `@nx/esbuild:esbuild` targets, ensuring cache hashes properly reflect changes to the workspace root `tsconfig.json`. Additionally, exports `TS_SOLUTION_SETUP_TSCONFIG_INPUT` from `@nx/js` so other Nx packages can reuse this constant for their own executors and plugins. |
||
|
|
4bbd4b1adc |
chore(repo): migrate nx repo to eslint v9 flat config (#35359)
## Current Behavior The nx repo uses the legacy eslintrc format (`.eslintrc.json`, `.eslintignore`) with ESLint v8 and outdated plugin versions. Several of those plugins ship code that crashes under ESLint v9 (`context.getScope` removed, etc.), and the `@nx/eslint` / `@nx/eslint-plugin` sources still reference APIs removed in v9 (`Linter.defineParser`, `Linter.defineRule`, classic `Linter.Config` shape). ## Expected Behavior Every project in the repo uses an `eslint.config.mjs` flat config, the ESLint ecosystem is on the latest v9-compatible versions, and `@nx/eslint` / `@nx/eslint-plugin` sources compile and test cleanly against the v9 type split. ### Main changes - Replaced every `.eslintrc.json` / `.eslintignore` with an `eslint.config.mjs`. - Rewrote the root `eslint.config.mjs`: - Exports a named `baseConfig` that leaf configs import, plus a default export that opts out of linting (`**/*` ignored) so the root acts as a shared base and isn't lint-checked directly. - Drops `FlatCompat` in favor of native plugin imports. - Exports shared `reactHooksV7Off`, `e2eTestOnlyIgnores`, and a `storybookConfigs` wrapper that filters v10's preset down to `storybook/*` rules (the preset references foreign rules like `import-x/*` that we don't register). - Cleaned up leaf configs emitted by the generator: deduplicated file entries, merged split `package.json` blocks, fixed the jsonc parser namespace import after v3 dropped its default export. - Scoped the 15 e2e projects to `*.test.ts` files only via a shared export. - Bumped the ESLint ecosystem to the latest v9-compatible versions: `eslint@^9.39.4`, `@eslint/js@^9.39.4`, `@typescript-eslint/*@^8.58.2`, `eslint-plugin-storybook@^10.3.5`, `eslint-plugin-react-hooks@^7.1.0`, `eslint-plugin-jsx-a11y@^6.10.2`, `eslint-plugin-import@^2.32.0`, `eslint-plugin-playwright@^2.10.1`, `eslint-plugin-cypress@^6.3.1`, `eslint-plugin-jest@^29.15.2`, `toml-eslint-parser@^1.0.3`, `jsonc-eslint-parser@^3.1.0`, `angular-eslint@^21.3.1`. Dropped `@eslint/eslintrc`, `@types/eslint`, `@types/eslint__js`. - Aligned `@nx/eslint` source with the v9 type split: `Linter.Config` → `Linter.LegacyConfig`, `ESLint.Options` → `ESLint.LegacyOptions` wherever the underlying shape is eslintrc. - Rewrote `@nx/eslint-plugin` rule specs (`dependency-checks`, `enforce-module-boundaries`) as flat-config inline tests since `Linter.defineParser`/`defineRule` were removed in v9. - Aligned react/angular/expo/react-native add-linting helpers with the v9 type split. - Migrated `tools/eslint-rules` specs from `TSESLint.RuleTester` (legacy config, rejected by v9's flat Linter) to `@typescript-eslint/rule-tester`; added `isolatedModules: true` so ts-jest resolves the new types under `module: node16`. - Downgraded the new react-hooks v7 rules to `off` via a shared export so the migration doesn't require rewriting legacy code. - Auto-fixed unused eslint-disable directives (`linterOptions.reportUnusedDisableDirectives` defaults to warn in v9). - Ignored `packages/workspace/**/__fixtures__/**` in lint and updated the affected snapshot so the fixture matches what the jest generator templates actually emit. ### Note on ESLint v10 This PR stays on ESLint v9. A few plugins we rely on (`eslint-plugin-import`, `eslint-plugin-jsx-a11y`, `eslint-plugin-react`) still don't declare v10 peer support. The jump to v10 will happen in a follow-up PR once those plugins publish v10-compatible releases. |
||
|
|
cf9c96afcb |
fix(node): split package-manager exec command for VS Code launch.json (#35295)
## Current Behavior When generating a `@nx/node:application` from a pnpm workspace, the generated `launch.json` sets `runtimeExecutable` to the full `getPackageManagerCommand().exec` string (e.g. `"pnpm exec"`). On Windows, VS Code rejects this: ``` Can't find Node.js binary "pnpm exec": path does not exist. Make sure Node.js is installed and in your PATH, or set the "runtimeExecutable" in your launch.json. ``` The same issue affects npm (`npm exec --`) and yarn (`yarn exec`). ## Expected Behavior `runtimeExecutable` should be a real binary path (`pnpm`, `npm`, `yarn`), and the `exec` / `exec --` tokens should live in `runtimeArgs`. ## Fix Split `getPackageManagerCommand().exec` on whitespace, feed the first token into `runtimeExecutable`, and prepend the remaining tokens to `runtimeArgs`. Bun (`bunx`) is unaffected because it has no space. ## Related Issue(s) Fixes #35276 |
||
|
|
dc479c50a5 |
fix(js): stop generating baseUrl in tsconfig, use ./ prefix for path mappings (#34965)
## Current Behavior Nx generators set `compilerOptions.baseUrl: "."` in generated tsconfig files and write path mappings as bare relative paths (e.g., `my-lib/src/index.ts`). `baseUrl` is deprecated in TS 6 and removed in TS 7. ## Expected Behavior Nx no longer generates `baseUrl` in any tsconfig. Path mappings use `./` prefix (e.g., `./my-lib/src/index.ts`), making them relative to the tsconfig file without needing `baseUrl`. Existing user tsconfigs with `baseUrl` continue to work correctly. ### Generator and template changes - Remove `baseUrl` from all templates and generator code - `addTsConfigPath` normalizes lookup paths with `./` prefix - Move and remove generators handle `./`-prefixed paths correctly - Angular secondary entry points and Remix server entry paths use `./` prefix ### `resolvePathsBaseUrl` helper New function (in `ts-config.ts`, duplicated in `register.ts`) that walks the tsconfig `extends` chain to determine the correct directory for resolving `paths` values. Finds where `paths` is defined, then looks for the applicable `baseUrl` from that point toward the root — ignoring child overrides that don't apply to the paths-defining tsconfig. When no `baseUrl` applies, returns the directory of the tsconfig that defines `paths`. All path resolver plugins and buildable-libs-utils use this helper. ### Runtime and bundler fixes for baseUrl-less tsconfigs - **Rollup**: resolve path mappings to absolute in compiler options override using `resolvePathsBaseUrl`; use original tsconfig path (not tmp) for resolution base - **Module Federation**: add `workspaceRoot` to `resolve.modules` in all 8 MF plugin variants (Angular/React webpack, Angular/React rspack, webpack SSR, rspack SSR, Angular rspack plugin, rspack plugin) so workspace-relative expose paths resolve without `baseUrl` - **Next.js/Jest**: null out SWC `resolvedBaseUrl` in generated jest configs to prevent SWC from doing incorrect path alias resolution; Nx jest resolver handles this via `resolvePathsBaseUrl` - **register.ts**: use `resolvePathsBaseUrl` for correct path alias registration - **Path resolver plugins** (webpack, rspack, vite, expo, react-native, jest, react component testing): use `resolvePathsBaseUrl` for correct path resolution - **buildable-libs-utils**: resolve tmp tsconfig paths to absolute so they work without `baseUrl` - **eslint-plugin**: handle `./`-prefixed paths in AST utils ## Related Issue(s) Fixes #32958 |
||
|
|
887fca4ac8 |
fix(repo): narrow copy-assets outputs to prevent overlap with build-base (#35097)
## Current Behavior
Broad globs in `assets.json` (`**/*.json`, `**/*.js`, `**/*.d.ts`) cause
`copy-assets` targets to claim cache ownership over files also produced
by `build-base` (tsc). Even though a recent change reordered
`copy-assets` to run before `build-base` (reducing the likelihood of the
race condition), the underlying task ownership model is still broken —
both targets claim overlapping files in their output patterns.
## Expected Behavior
Each target exclusively owns its output files. `copy-assets` only claims
non-tsc assets (templates, type declarations, native artifacts), and
`build-base` owns all compiler outputs.
## Changes
**37 `assets.json` files** — replaced broad extension globs with narrow,
destination-safe patterns: template dirs (`**/files/**`), schema type
declarations (`src/**/schema.d.ts`), non-tsc extensions (`.jar`,
`.node`, `.wasm`, `.md`), and explicit file paths for package-specific
assets.
**30 `tsconfig.lib.json` files** — removed `**/*.json` from `include` so
tsc only compiles TypeScript. JSON files are now handled by copy-assets
with explicit entries
(`@(package|executors|generators|migrations).json`,
`src/**/schema.json`).
**Exception:** jest and vite use `import('./schema.json')` which
requires JSON in tsconfig scope with `composite: true`. These keep
`src/**/schema.json` in tsconfig.
**vite** — excludes `test-utils.ts` from lib build (only used by specs)
and includes it in `tsconfig.spec.json`.
|
||
|
|
37eb4ecde4 |
fix(bundling): bump esbuild for new projects to a version compatible with vite 8 (#35132)
## Current Behavior Newly generated JS/esbuild-based projects still default `esbuild` to `^0.19.2`. That conflicts with Vite 8 which requires `esbuild ^0.27.0`. ## Expected Behavior Newly generated projects should default to an `esbuild` version compatible with Vite 8. If a workspace already has `esbuild` installed, generators should preserve that version instead of blindly bumping it, and Vite init should fall back to Vite 7 with a warning when the installed `esbuild` range is incompatible with Vite 8. --------- Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com> |
||
|
|
a040a93791 |
fix(repo): add copy-assets plugin and migrate all packages from legacy-post-build (#34994)
## Current Behavior Each package defines a `legacy-post-build` target in `project.json` with inline asset copy configuration. Inputs are not accurately declared, leading to sandbox violations in CI. The asset globs, ignores, and outputs must be manually kept in sync across 37 packages. ## Expected Behavior A `copy-assets` createNodesV2 plugin reads `assets.json` from each package and automatically generates the target with: - Inputs derived from asset globs (positive patterns first, then negations) - Outputs derived using the same dest logic as `CopyAssetsHandler` - `dependentTasksOutputFiles` for gitignored build artifacts (jars, native binaries) - Automatic `outDir` exclusion from asset copies ## Changes **New infrastructure:** - Add `copy-assets` createNodesV2 plugin in `tools/workspace-plugin` - Add `copy-assets` executor (simplified from `legacy-post-build` — just copies assets, no package.json field manipulation) - Extract `normalizeAssets` and `getAssetOutputPath` into reusable module in `packages/js` - Add `copyReadme` namedInput for copy-readme build targets **Migration (all 37 packages):** - Create `assets.json` for every package defining what to copy - Remove all `legacy-post-build` targets from project.json files - Remove `legacy-post-build` target defaults from nx.json - Remove redundant `copy-local-native` target (replaced by `.node`/`.wasm` in asset glob) **Cleanup:** - Remove dead config: `creator-files` globs, non-existent template files, typo'd directory names - Use root-level `tsconfig*.json` ignore instead of recursive (so template tsconfigs in `files/` dirs are still copied) - Replace `!(*.ts)` extglob patterns with explicit globs (extglobs don't work correctly in Nx inputs) - Fix gradle lint: add `buildTargets: ["build-base"]` and `tslib` dependency - Add jar outputs to maven `_package` target for correct `dependentTasksOutputFiles` resolution **Other fixes:** - Exclude `.swc` directories from sandbox write checks - Enable typecheck for `angular-rspack` packages (remove `addTypecheckTarget: false`) - Pin workspace-plugin deps to explicit versions, add `@nx/plugin` to root package.json --------- Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com> Co-authored-by: FrozenPandaz <FrozenPandaz@users.noreply.github.com> |
||
|
|
732a08c77d |
chore(core): build nx to local dist and use nodenext (#34111)
## Current Behavior The `nx` package compiles its TypeScript output to `../../dist/packages/nx/` (relative to the package root), which places build artifacts outside the package directory at the repo root level (`dist/packages/nx/`). This makes the package structure harder to reason about, complicates the build pipeline, and doesn't align with how most packages organize their output. The package uses `"module": "commonjs"` with basic module resolution, which limits future migration paths toward ESM. ## Expected Behavior The `nx` package now builds to a local `dist/` directory within the package itself (`packages/nx/dist/`). This is a cleaner, more standard layout — like having your tools in your own toolbox instead of scattered across the workshop. ### Key changes: **Build configuration (`packages/nx/tsconfig.lib.json`):** - `outDir` changed from `../../dist/packages/nx` to `dist` (local to package) - `module` changed to `nodenext` with `moduleResolution: nodenext` - Updated `include` patterns to explicitly list source directories **Package entry points (`packages/nx/package.json`):** - `bin` paths updated: `./bin/nx.js` → `./dist/bin/nx.js` - Added `"type": "commonjs"` explicitly - Added comprehensive `exports` map with `@nx/nx-source` condition for dev/test resolution back to TS source - Added `postinstall` path update to `./dist/bin/post-install` **Module resolution fixes:** - Created `src/utils/handle-import.ts` — a CJS-first import utility that falls back to ESM `import()` for ESM-only packages, providing a single migration point for future ESM work - Converted dynamic `await import()` calls to `require(require.resolve())` pattern where needed to satisfy `nodenext` extension requirements - Plugin worker spawn path now uses correct `.ts`/`.js` extension based on runtime context (source vs compiled) **Test infrastructure:** - Added custom `jest-resolver.js` for the `nx` package that resolves `nx/...` imports using the `@nx/nx-source` exports condition, so tests run against TS source - Updated `jest.preset.js` with SWC transformer configuration - Added chalk mock for test compatibility **CI and tooling:** - Conformance check updated to build `workspace-plugin` first (the Nx Cloud runner lacks `@swc-node/register` for TS resolution) - Conformance rule paths in `nx.json` now point to compiled `dist/workspace-plugin/src/...` output - Added `dist` to eslint ignore patterns to prevent linting compiled output - Added workspace-plugin build target and updated its dependencies **Other fixes:** - Various import path fixes across `create-nx-workspace`, gradle, and other packages to work with `nodenext` resolution - Updated e2e test paths to reference the new dist location - Fixed `.gitignore` and `.npmignore` for the new output structure ## Related Issue(s) Internal infrastructure improvement — no external issue. --------- Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com> Co-authored-by: Coly010 <Coly010@users.noreply.github.com> Co-authored-by: FrozenPandaz <jasonjean1993@gmail.com> |
||
|
|
cb6452ce93 |
fix(misc): address security CVE cluster (copy-webpack-plugin, koa, minimatch) (#34708)
## Current Behavior Several security-related issues reported: 1. **copy-webpack-plugin** (#34632): `@nx/webpack` and `@nx/next` pin `copy-webpack-plugin@^10.2.4` which transitively depends on `serialize-javascript@^6.0.1` (vulnerable) and `fast-glob` (supply-chain risk). 2. **koa** (#34621): `@nx/module-federation` transitively pulls `koa@3.0.3` via `@module-federation/dts-plugin`, which is vulnerable to CVE-2026-27959 (Host Header Injection, fixed in koa 3.1.2). 3. **css-minimizer-webpack-plugin**: `@nx/webpack` pins `^5.0.0` which also depends on vulnerable `serialize-javascript@^6.0.1`. 4. **@module-federation/enhanced**: Versions `<2.1.0` transitively install vulnerable `koa` via `dts-plugin`. 5. **Next.js**: Versions `16.0.x` are vulnerable to GHSA-9g9p-9gw9-jx7f (Image Optimizer DoS) and GHSA-5f7q-jpqc-wp7h (PPR Resume memory consumption). 6. **minimatch** (#34701): User reports minimatch vulnerability, but the Nx pnpm catalog already pins the patched version `10.2.4`. No code change needed — users should delete their lockfile and reinstall. ## Expected Behavior 1. **copy-webpack-plugin** bumped to `^14.0.0` which uses `serialize-javascript@^7.0.3` (patched). Added `noErrorOnMissing: true` to all 3 copy-webpack-plugin usage sites to handle the v14 breaking change where missing glob patterns now throw errors by default. 2. **css-minimizer-webpack-plugin** bumped to `^8.0.0` which uses `serialize-javascript@^7.0.3` (patched). 3. **koa** bumped to `^3.1.2` in `@nx/node` versions.ts. `@module-federation/dts-plugin@2.1.0` completely removes koa dependency. 4. **@module-federation/enhanced**, **runtime**, **sdk** bumped to `^2.1.0` across all packages (`@nx/module-federation`, `@nx/react`, `@nx/angular`, `@nx/rspack`). Added `noErrorOnMissing` fix for `@module-federation/enhanced` 2.x `runtime-library-control.plugin.ts` compatibility. 5. **Next.js** bumped to `~16.1.6` and `eslint-config-next` to `^16.1.6`. 6. **minimatch** — no change needed, already resolved. ### Migrations added (22.6.0-beta.10) - `@nx/module-federation`: Bump MF packages to `^2.1.0` - `@nx/react`: Bump `@module-federation/enhanced` to `^2.1.0` - `@nx/angular`: Bump `@module-federation/enhanced` to `^2.1.0` - `@nx/node`: Bump `koa` to `^3.1.2` - `@nx/next`: Bump `next` to `~16.1.6` ### Skipped - **esbuild** (`<=0.24.2`, moderate severity, dev server only): Fix requires breaking change jump from `^0.19.2` to `0.25+`. Will address separately. ## Testing Created a fresh Nx workspace with all affected plugins to verify `npm audit` is clean after changes: - `@nx/next` (nextapp) - `@nx/webpack` (webpackapp) - `@nx/rspack` (shell, remote1, remote2 via Module Federation) - `@nx/module-federation` (shell + remotes with MF config) - `@nx/react` (MF host/remotes) - `@nx/node` + koa (api) ``` ├── apps │ ├── api # @nx/node (koa) │ ├── nextapp # @nx/next │ ├── remote1 # @nx/react + rspack + MF │ ├── remote2 # @nx/react + rspack + MF │ ├── shell # @nx/react + rspack + MF (host) │ └── webpackapp # @nx/webpack ``` Post-change audit result — only remaining issue is esbuild (moderate, skipped intentionally): ``` # npm audit report esbuild <=0.24.2 Severity: moderate esbuild enables any website to send any requests to the development server and read the response - https://github.com/advisories/GHSA-67mh-4wv8-2f99 fix available via `npm audit fix --force` Will install esbuild@0.27.3, which is a breaking change 1 moderate severity vulnerability ``` ## Related Issue(s) Fixes #34632 Fixes #34621 Fixes #34701 |
||
|
|
e3eedf9e94 |
docs(misc): update the docs to use more direct language (#34264)
<!-- 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 --> ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes # |
||
|
|
2bd8ef3f72 |
feat(js): bump swc to latest versions (#34215)
## Current Behavior SWC versions are a few minors behind. ## Expected Behavior SWC versions are up to date and are being managed via PNPM Catalogs |
||
|
|
6f85b83fd3 |
cleanup(repo): format all files (#33902)
Format all files after Prettier v3 was merged. |
||
|
|
62c13c5477 |
feat(misc): support prettier v3 (#33898)
## Current Behavior Nx doesn't generate projects with Prettier v3. ## Expected Behavior Nx should generate projects with Prettier v3. ## Related Issue(s) Fixes #30801 |
||
|
|
3db0fb2ce9 |
fix(node): use @swc/helpers instead of tslib when compiler is swc (#33885)
When using `@nx/node:library` generator with `--compiler=swc`, the generator was incorrectly adding `tslib` as a dependency instead of `@swc/helpers`. This change fixes two issues: 1. Pass the correct bundler (matching the compiler) to jsLibraryGenerator so it adds the correct helper dependency to the project's package.json 2. Update ensureDependencies to only add tslib when compiler is tsc Fixes #31202 |
||
|
|
7f6db63f91 |
fix(node): sourceMaps option to sourceMap in webpack config (#33333)
## Current Behavior
when I run the below nx workspace command
nx g @nx/express:app kafka-service --directory=apps/kafka-service
--e2eTestRunner=none
the apps/kafka-service/webpack.config.json is generated with the below
lines
const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin');
const { join } = require('path');
module.exports = {
output: {
path: join(__dirname, 'dist'),
...(process.env.NODE_ENV !== 'production' && {
devtoolModuleFilenameTemplate: '[absolute-resource-path]',
}),
},
plugins: [
new NxAppWebpackPlugin({
target: 'node',
compiler: 'tsc',
main: './src/main.ts',
tsConfig: './tsconfig.app.json',
assets: ["./src/assets"],
optimization: false,
outputHashing: 'none',
generatePackageJson: true,
sourceMaps: true,
})
],
};
there is no such property in NxAppWebpackPluginOptions called
**sourceMaps**, hence source maps are not generated
the correct property is **sourceMap**
## Expected Behavior
module.exports = {
output: {
path: join(__dirname, 'dist'),
...(process.env.NODE_ENV !== 'production' && {
devtoolModuleFilenameTemplate: '[absolute-resource-path]',
}),
},
plugins: [
new NxAppWebpackPlugin({
target: 'node',
compiler: 'tsc',
main: './src/main.ts',
tsConfig: './tsconfig.app.json',
assets: ["./src/assets"],
optimization: false,
outputHashing: 'none',
generatePackageJson: true,
sourceMap: true,
})
],
};
## Related Issue(s)
Fixes #
|
||
|
|
cac7f6c3e8 |
fix(node): set generatePackageJson:false for TS Solution workspaces (#33606)
## Current Behavior In TS Solution setups, we generate webpack config with `generatePackageJson: true`. This is confusing and unneeded. It should be set to false in TS Solution repos. ## Expected Behavior Set `generatePackageJson: false` in webpack config for TS Solution Setups Closes NXC-3521 |
||
|
|
50cf84f758 |
chore(repo): update nx to 22.1.0-rc.2 (#33464)
Updating Nx from 22.1.0-beta.8 to 22.1.0-rc.2 |
||
|
|
62d0ad7f25 |
chore(repo): rename jest.config.ts to jest.config.cts to be compat with Node 24 strip types (#33401)
This PR is just for the repo itself to use `.cts` to explicitly use CJS for jest config. Node 24 strip types so having `.ts` files with ESM syntax even though we're previously transpiling them to CJS is a problem. |
||
|
|
9b5768e7fe |
fix(testing): use .cts config files for Jest 30+ to fix __dirname issues (#33349)
When using Jest 30 with SWC, users are seeing an error where `__dirname` is not defined for ESM modules. This is because the `.ts` extension is type-stripped by Node 22.17/24+ via checking for [`process.features.typescript`](https://github.com/jestjs/jest/blob/fe7f28c9d1941f5c2726831cd9d9e479b401610e/packages/jest-config/src/readConfigFileAndSetRootDir.ts#L46). This means that instead of using the `commonjs` we set for `ts-node`, normal Node resolution kicks in, and is now treating `jest.config.ts` as ESM. This PR fixes this issue by using an explicit `.cts` extension, which forces CommonJS that we assume for Jest configs. Note: For Jest 29 or earlier we need to keep `jest.config.ts` since the `.cts` extension is not supported prior to Jest 30. There's also a fix for an existing issue where using `module.exports` of anything else from `@types/node` will error out if `tsconfig.json` has a `types` field but does not include `node`. See: https://www.loom.com/share/7ebe3c90a70e4ec7bfa53cbcccaaea7d Fixes #32236 --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
f76f1ce3df |
chore(repo): dogfood pnpm catalogs (#33232)
Dogfoods the Pnpm Catalogs feature in the Nx repo. This is the first step to move all dependencies to Pnpm Catalogs definitions. More work will be done incrementally later as we consolidate package versions across the repository. The initial list of dependencies moved to Pnpm Catalogs is: - Angular packages - React packages - TypeScript packages - Jest packages - Rspack packages - Some common utilities |
||
|
|
3047fbda9e |
fix(core): should find dockerfiles to suggest installing docker plugin (#33234)
## Current Behavior `nx init` does not search for `Dockerfile` patterns to suggest adding the `@nx/docker` plugin. ## Expected Behavior `nx init` finds and suggests `@nx/docker` plugin Fixes NXC-3319 |
||
|
|
1002ad5198 |
fix(node): migrate to koa 3.0.3 (#33208)
Update `koa` to `3.0.3` |
||
|
|
836034172c |
chore(repo): disable duplicated typecheck targets if the project already uses tsc to build (#32926)
This PR removes redundant `typecheck` targets from projects already building with `tsc`. - Add `addTypecheckTarget: false` to projects using `tsc` as `build-base`. - Exclude `e2e` and `nx-dev` projects from having `tsc` build inferred but leave the `typecheck` target Note: angular-rspack and angular-rspack-compiler has an issue where `@nx/vite/plugin` is inferring the typecheck target. We may want to check `addTypecheckTarget` for that plugin as well. <!-- 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` --> Closes NXC-3208 |
||
|
|
4f9eeb4fb1 |
feat(webpack)!: remove deprecated deleteOutputPath and sassImplementation options (#32828)
The webpack package contains deprecated options that were marked with TODO(v22) comments for removal: - deleteOutputPath option - sassImplementation option These deprecated options were still being referenced in the codebase and schema files, potentially causing confusion for users. Remove the deprecated options from the webpack package to clean up the API for v22: - Remove deleteOutputPath option from the webpack executor and related configurations (use Webpack's output.clean option instead) - Remove sassImplementation option from the webpack executor and related configurations (sass-embedded is now the default) - Add a migration to automatically update existing workspaces that use these deprecated options Closes NXC-3108 --------- Co-authored-by: Colum Ferry <cferry09@gmail.com> Co-authored-by: nx-cloud[bot] <71083854+nx-cloud[bot]@users.noreply.github.com> |
||
|
|
c7d540614c | docs(misc): update new subtagline | ||
|
|
ec6b707d13 |
fix(js): use a unique typescript custom condition name for the workspace (#32429)
## Current Behavior Workspaces using the new setup with TS project references + package manager workspaces are generated with a custom condition named `development`. Projects have a conditional `development` entry point that points to the source to improve the DX in the repo. This condition name can cause issues with published libraries because it's not unique, and some build tools automatically pick it up. While using it locally in the workspace is safe because the source file exists, this is not the case when the published library is used outside the workspace. ## Expected Behavior Workspaces using the new setup with TS project references + package manager workspaces should be generated with a unique custom condition named after the name in the root `package.json` file. Projects should have a conditional entry point matching that name and pointing to the source to improve the DX in the repo. Users can customize the custom condition and name it something else as long as it starts with `@nx-source/` so that Nx generators and helpers can identify it. Additionally, in the unlikely scenario that the root `package.json` doesn't have a `name` set, Nx will fall back to use `@nx/source`. This new behavior matches an emerging pattern of using scoped custom export conditions for pointing to the source: - [Announcing TypeScript 5.7](https://devblogs.microsoft.com/typescript/announcing-typescript-5-7/#path-rewriting-for-relative-paths:~:text=As%20a%20result%2C%20if%20you%E2%80%99ve%20been%20using%20a%20workspace%2Dstyle%20layout%20with%20multiple%20packages%20referencing%20each%20other%2C%20you%20might%20need%20to%20use%20conditional%20exports%20with%20scoped%20custom%20conditions%20to%20make%20this%20work%3A) - [Live types in a TypeScript monorepo](https://colinhacks.com/essays/live-types-typescript-monorepo#:~:text=Here%27s%20how%20a%20custom%20condition%20might%20look%20in%20your%20package.json.%20There%27s%20nothing%20special%20about%20the%20string%20%22%40colinhacks/zod%22%20here!%20It%20could%20be%20anything.) - [Loading from Source](https://github.com/isaacs/tshy?tab=readme-ov-file#loading-from-source) ## Related Issue(s) Fixes #31332 |
||
|
|
6ce1061471 |
fix(misc): update @types/node to v20.19.9 to support fetch API (#32092)
## Current Behavior Nx currently installs an outdated `@types/node` version (18.16.9) which lacks TypeScript definitions for the native `fetch` API introduced in Node.js 18. This causes "fetch is undefined" TypeScript errors in NestJS projects and other Node.js applications when using webpack transformers or other build tools. ## Expected Behavior The `fetch` API should be properly typed in TypeScript without requiring additional type packages or workarounds. Users should be able to use the native fetch API in Node.js applications without TypeScript compilation errors. ## Related Issue(s) Fixes #31637 Fixes https://github.com/nrwl/nx/issues/29714 --------- Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com> Co-authored-by: Colum Ferry <cferry09@gmail.com> |