fix(core): speed up nx --version by avoiding heavy imports#35326
fix(core): speed up nx --version by avoiding heavy imports#35326FrozenPandaz merged 6 commits intomasterfrom
Conversation
✅ Deploy Preview for nx-docs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for nx-dev ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
View your CI Pipeline Execution ↗ for commit 75a7b19
☁️ Nx Cloud last updated this comment at |
5e6ea4d to
40eeb0b
Compare
3d3fcbf to
a032faa
Compare
6c42e9b to
ce0d2ff
Compare
…t path The bin/nx.ts entry point eagerly imported the daemon client, dotenv loader, analytics + perf-logging stack, and init-local for every invocation, even trivial ones like --version. That added ~225ms of unnecessary module load time before the first instruction of main() ran. This commit: - Lazy-loads those heavy modules inside the code paths that actually need them (cloud commands, local install handoff, etc.). - Adds a --version fast path at the top of main() that exits before any heavy module is touched. - Makes src/utils/perf-logging.ts lazy-require analytics / daemon logger inside the PerformanceObserver callback, so simply importing the module no longer pulls in the native binding (~63ms saved). - Updates the bench:version benchmark (and friends) to call ./node_modules/.bin/nx directly instead of pnpm exec nx, removing ~220ms of pnpm wrapper overhead from the measurement. Result for nx --version: - nx-only contribution: ~220ms -> ~10ms - end-to-end (./node_modules/.bin/nx --version): ~260ms -> ~49ms
ce0d2ff to
8b96c41
Compare
The previous fast-path refactor guarded cleanup with require.cache[require.resolve(...)] so modules would only be cleaned up if they had actually been loaded. But require.resolve throws synchronously when the module can't be resolved, which broke the exit flow in published nx installs (observed as "Cannot find module '../src/utils/db-connection'" in create-nx-workspace e2e tests and masked the real error). - Move the db-connection exit handler into db-connection.ts so it only registers when the module is actually imported. - Track analyticsStarted via a plain flag in bin/nx.ts instead of probing require.cache with require.resolve.
Gives proper TypeScript types on the lazily-loaded modules without 'as typeof import(...)' casts. No measurable perf difference on the --version fast path since it short-circuits before any of these fire. Directory imports (analytics/) need an explicit /index.js because dynamic import() uses ESM resolution rules.
…) [Self-Healing CI Rerun]
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
It's only used internally by the self-registered exit handler now, so there's no reason to expose it.
…tdown The db-connection module now self-registers a process 'exit' handler that cleans up connections, so the daemon shutdown path doesn't need to call it explicitly.
|
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 --version(and other trivial CLI invocations) eagerly load the daemon client, dotenv loader, analytics + perf-logging stack, andinit-localat the top ofbin/nx.ts. That's ~225ms of unrelated module load time beforemain()starts running.On a typical workspace, the cost looks like:
daemonClientimportperf-logging(loadsanalytics→ native binding)init-localdotenvanalytics-promptEnd-to-end:
nx --versionwas ~440ms viapnpm exec.Expected Behavior
--version(and other no-workspace fast paths) only load what they actually need.This PR:
--versionfast path at the top ofmain()that exits before any heavy module is touched.src/utils/perf-logging.tsto lazy-requireanalytics/ daemon logger inside thePerformanceObservercallback. Importing the module no longer pulls in the native binding.benchmarks/bench:*scripts to invoke the workspace nx directly vianode ../packages/nx/dist/bin/nx.jsinstead ofpnpm exec nx, which removes ~220ms of pnpm wrapper overhead from the measurement and works on CI agents (which don't sync per-projectnode_modules/.bin).goals.jsonis adjusted to the new floor.Benchmark Results
Measured locally against the
benchmarks/workspace (1,110 projects). Deltas are shown as(vs Goal | vs Baseline).versionclears the goal; the other benchmarks pick up the wrapper-overhead delta too, but several are still above goal and remain targets for follow-up work.Related Issue(s)
N/A — internal performance work on the
speed-versionbranch.