chore(devkit): build devkit to local dist and use nodenext#34946
Conversation
✅ Deploy Preview for nx-dev ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for nx-docs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
View your CI Pipeline Execution ↗ for commit b8afee4
☁️ Nx Cloud last updated this comment at |
87bbd64 to
2e8ae9a
Compare
4413af3 to
712c14f
Compare
d61c9ee to
5f5f694
Compare
90f9385 to
86f4f58
Compare
86f4f58 to
b847030
Compare
778943b to
2465c46
Compare
abfc212 to
7d438c9
Compare
There was a problem hiding this comment.
Nx Cloud has identified a flaky task in your failed CI:
🔂 Since the failure was identified as flaky, we triggered a CI rerun by adding an empty commit to this branch.
🔔 Heads up, your workspace has pending recommendations ↗ to auto-apply fixes for similar failures.
🎓 Learn more about Self-Healing CI on nx.dev
1281623 to
e0ac70a
Compare
eb51156 to
8fe5520
Compare
Mirrors the nx package change from #34111. The devkit package now builds to packages/devkit/dist/ instead of dist/packages/devkit/. Key changes: - tsconfig.lib.json: outDir to dist, nodenext module/moduleResolution - package.json: added type:commonjs, exports map with @nx/nx-source condition - project.json: updated build targets for local dist paths - Added .npmignore to exclude source from publish - Renamed README.md to readme-template.md (generated README is gitignored) - Updated all external references (nx-release.ts, angular-rspack patch) chore(core): use npm-published nx packages for workspace-plugin Remove workspace:* links to @nx/devkit, @nx/js, @nx/plugin, nx, and @nx/conformance from workspace-plugin. These are already installed as npm packages in root devDependencies, so workspace-plugin resolves them via hoisting. This breaks the circular dependency where workspace-plugin needed devkit built before it could load. Also added @nx/plugin to root devDependencies and disabled dependency-checks lint rule for workspace-plugin. fix(devkit): add explicit exports for directory-based modules The wildcard export pattern `./src/utils/*` resolves to `./dist/src/utils/catalog.js` but the actual file is at `./dist/src/utils/catalog/index.js`. Added explicit entries for catalog, async-iterable, and plugin-migrations directories. fix(devkit): update astro-docs devkit entry point paths The d.ts files now live in packages/devkit/ instead of dist/packages/devkit/ after the local dist migration. fix(angular): disable prefer-standalone lint rule for lib in e2e test The test only disabled @angular-eslint/prefer-standalone for app1 but not lib1, causing lint failures when angular-eslint enables the rule by default. fix(devkit): simplify exports map to avoid subpath resolution issues fix(devkit): add explicit exports for directory modules and nested paths cleanup(devkit): move src subpath imports to devkit internal All internal imports like @nx/devkit/src/utils/catalog are now re-exported from @nx/devkit/internal. This removes the need for src subpath exports in package.json, which caused issues with Node.js exports map resolution for nested paths. fix(devkit): update remaining e2e test imports from devkit src to internal fix(core): add nx-source condition to shared jest resolver fix(misc): inline string utils in e2e tests instead of importing from devkit internal chore(repo): remove main
…eration The devkit tsconfig.lib.json excludes dist/ and only includes *.ts and src/**/*.ts. Since TypeDoc copies this tsconfig to a temp directory, the dist/index.d.ts entry point wasn't in scope. Add an absolute path include for devkit's dist .d.ts files and remove 'dist' from the exclude list.
…lf-Healing CI Rerun]
Remove dead path mappings and the in-memory include manipulation. TypeDoc receives absolute entryPoints (packages/devkit/dist/*.d.ts) and resolves nx subpaths via workspace-linked node_modules + nx's exports map, so neither is needed.
Without this, TypeDoc errors with 'entry point is not referenced by the files or include option in your tsconfig' and generates zero devkit reference pages.
The @angular-eslint generator now emits double-quoted rule names, so the existing single-quote string replacement no-ops. Use a regex that matches either quote style and apply it to both app1 and lib1.
devkit now builds to packages/devkit/dist with a proper exports map and
is reachable through workspace-linked node_modules. require('@nx/devkit')
resolves correctly from inside @nx/angular-rspack without the manual
Module._resolveFilename interception.
The patchModuleFederationRequestPath helper stays for now — module
federation hasn't been migrated to local dist yet.
Declaration files only emit to dist/ (declarationDir in tsconfig.lib.json), which is already ignored. The wildcard pattern is dead.
findPluginForConfigFile was added but never referenced.
| "./internal": { | ||
| "@nx/nx-source": "./internal.ts", | ||
| "types": "./dist/internal.d.ts", | ||
| "default": "./dist/internal.js" | ||
| }, |
There was a problem hiding this comment.
We are gonna break a ton of community plugins if we dont leave the export path for the project name and root utils (and maybe the create nodes hash utils) as exported just as an FYI
## Current Behavior
`@nx/devkit`'s `build-base` target overrode `outputs` in `project.json`:
```json
"outputs": [
"{projectRoot}/dist/**/*.{js,cjs,mjs,d.ts}",
"{projectRoot}/*.d.ts",
"{projectRoot}/src/**/*.d.ts"
]
```
This override is missing `tsconfig.tsbuildinfo`. Any downstream task
whose inputs include `dependentTasksOutputFiles:
"**/*.{d.ts,d.cts,d.mts,tsbuildinfo}"` (e.g. `docker:build-base`) trips
a sandbox violation: when `tsc --build` walks project references it
reads devkit's tsbuildinfo, but Nx never registered that file as a dep
output, so the read isn't covered by any declared input.
The same gap exists in the `dist-build-migration` Claude skill, so every
package migrated with that playbook would reproduce the violation.
Sandbox report that surfaced this:
https://staging.nx.app/runs/HNBpzgdeNi/task/docker%3Abuild-base/sandbox-report-raw?sandboxReportId=10b903d8-b860-41c7-80b2-756b0541e690
## Expected Behavior
Drop the override entirely. The `@nx/js/typescript` plugin already reads
`outDir` and `tsBuildInfoFile` from `tsconfig.lib.json` and infers a
strictly more complete set of outputs:
```
{projectRoot}/dist/**/*.{js,cjs,mjs,jsx,json,d.ts,d.cts,d.mts}{,.map}
{projectRoot}/dist/tsconfig.tsbuildinfo
```
The inferred set picks up the tsbuildinfo plus
`.cjs`/`.mjs`/`.json`/`.d.cts`/`.d.mts`/`.map` that the manual override
was missing. Verified the violation is resolved:
```
$ pnpm nx show target inputs docker:build-base --check packages/devkit/dist/tsconfig.tsbuildinfo
✓ packages/devkit/dist/tsconfig.tsbuildinfo is an input for docker:build-base (depOutputs)
```
The `dist-build-migration` skill is updated to tell future migrations to
leave `build-base.outputs` to the plugin.
## Related Issue(s)
Follow-up to #34946.
## Current Behavior After #34946, `@nx/devkit` ships a strict `exports` map. Deep imports like `@nx/devkit/src/utils/...` and `@nx/devkit/src/generators/...` are no longer reachable through Node module resolution. Workspaces upgrading to `23.x` that reference those paths break with module-resolution errors at runtime / type-check time. ## Expected Behavior `nx migrate` runs an automated rewrite that covers the realistic shapes of these deep imports. The migration walks every `.ts`/`.tsx`/`.cts`/`.mts` file in the workspace and: 1. **Buckets named imports by symbol.** Each `@nx/devkit/src/...` import declaration is parsed via the TypeScript compiler API (lazy-loaded with `ensurePackage`). Specifiers in the `internal.ts` re-export list go to `@nx/devkit/internal`; all others go to `@nx/devkit`. Mixed imports split into two declarations. 2. **Falls back for non-named shapes.** Default imports, namespace imports, side-effect imports, `require(...)` calls, and dynamic `import(...)` get the specifier swapped to `@nx/devkit/internal` (the safe default — it re-exports every previously deep-importable symbol). 3. **Collapses duplicate imports.** A second AST pass groups `import { ... } from '@nx/devkit'` and `import { ... } from '@nx/devkit/internal'` declarations by `(specifier, isTypeOnly)`, merging each 2+ group into one declaration with deduplicated specifiers. This handles both the duplicates the rewrite produced and any pre-existing devkit imports the user already had. Edits are stacked via `applyChangesToString` (devkit's offset-tracking text-mutation helper), then `formatFiles` normalizes formatting. ### Example Before: ```ts import { Tree } from '@nx/devkit'; import { dasherize, names } from '@nx/devkit/src/utils/string-utils'; import { addPlugin } from '@nx/devkit/src/utils/add-plugin'; ``` After: ```ts import { Tree, names } from '@nx/devkit'; import { dasherize, addPlugin } from '@nx/devkit/internal'; ``` ### Tests 29 unit tests cover: single-bucket and mixed-bucket rewrites, `as` aliases, `import type` and inline `type` modifiers, multi-line imports, side-effect / default / namespace fallbacks, `require()` and dynamic `import()` fallbacks, quote-style preservation, pre-existing-import merge, public/internal independence, value-vs-type segregation, specifier deduplication, and a sanity test that every name in `DEVKIT_INTERNAL_SYMBOLS` is bucketed as internal. A user-facing `update-deep-imports.md` lives next to the implementation; the astro-docs build picks it up via the existing `packages/*/src/migrations/**/*.md` input glob. ## Related Issue(s) Follow-up to #34946.
) ## Current Behavior After running `nx-release` locally, `packages/devkit/package.json` is left modified in the working tree. The `nx-release.ts` script snapshots and restores the source `package.json` for every package whose source folder is the publish root (so the temporary edits made during `nx release version` — real version, expanded `workspace:*` deps, etc. — don't leak into the working tree). The list of those packages lives in `packagesToReset` near the top of `scripts/nx-release.ts`. When `@nx/devkit` was migrated to publish from its source folder in #34946, it was not added to that list, so its source `package.json` is no longer restored. ## Expected Behavior `packages/devkit/package.json` is restored to its committed contents after `nx-release` finishes (or is interrupted), matching the behavior already in place for `nx`, `dotnet`, `maven`, `angular-rspack`, and `angular-rspack-compiler`. ## Related Issue(s) N/A — internal release-tooling fix.
|
This pull request has already been merged/closed. If you experience issues related to these changes, please open a new issue referencing this pull request. |
Current Behavior
@nx/devkitbuilds to<workspaceRoot>/dist/packages/devkit/— outside its own package directory. Other packages reach into that shared workspacedist/to consume devkit, and consumers usingmoduleResolution: nodenextneed a custom Module._resolveFilename hack to find it.This is inconsistent with
nxitself, which already builds topackages/nx/dist/(#34111).Expected Behavior
@nx/devkitbuilds topackages/devkit/dist/and is consumed via a standardexportsmap. Workspace consumers resolve through normal pnpm symlinks; the@nx/nx-sourcecondition still lets in-repo code resolve to.tssource during dev.This unblocks the rest of the workspace from migrating in the same direction (a
dist-build-migrationClaude 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-sourcecondition wiring:packages/devkit/package.json—exportsmap,typesVersions,files,type: commonjs,main/typesrepointed todist/packages/devkit/tsconfig.lib.json—outDir: dist,nodenextmodule/resolutionpackages/devkit/project.json—build-baseoutputs,nx-release-publish.packageRoot,manifestRootsToUpdatepackages/devkit/internal.ts— re-exportssrc/utils/*andsrc/generators/*symbols (replaces the@nx/devkit/src/*deep-import pattern)packages/devkit/eslint.config.mjs— ignoredistpackages/devkit/{README.md → readme-template.md}— README is now generated, gitignored.gitignore— ignore the generatedpackages/devkit/README.mdscripts/nx-release.ts— devkit'spackage.jsonnow lives atpackages/devkit/package.json, notdist/packages/devkit/package.jsonscripts/patched-jest-resolver.js— adds@nx/nx-sourcecondition2. 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: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 thepatchDevkitRequestPathruntime 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 inastro-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'frompackages/devkit/eslint.config.mjssince.d.tsfiles only emit todist/(already ignored).fix(angular)eslint quote — quote-agnostic regex ine2e/angular/src/projects-linting.test.tsso the test still disablesprefer-standaloneafter the angular-eslint generator switched to double quotes (latent bug surfaced by CI).fix(testing)jest migration — removes a stray unused@nx/devkit/internalimport.e2e/{angular,next}/src/*.test.tslose access to@nx/devkit/src/utils/string-utils(e2e tests can't use/internal); inline equivalents using publicnames()API.e2e/nx-build/src/nx-build.test.tsupdates 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 patchKnown follow-up (not in this PR)
scripts/nx-release.tsstill hashackFixForDevkitPeerDependencies()(a band-aid from fix(devkit): restore peer dep range to 2 majors #32406 that re-adds<=to devkit'snxpeer-dep range afternx release versionstrips it). The proper fix is to setpreserveMatchingDependencyRanges: trueinpackages/devkit/project.jsonand delete the hack — that needs a release dry-run to verify, so it's queued separately.Related Issue(s)
Follow-up to #34111.