build(nx): run hot targets directly instead of via npm run - #324
Conversation
nx runs package.json script targets through the package manager: its
run-script executor spawns `npm run <script>`. With many tasks running in
parallel, an npm startup intermittently crashes inside npm's own config
loader ("Exit prior to config file resolving" / "call config.load() before
reading values", npm/cli#8425), failing the task before the underlying tool
runs — a flake unrelated to the code under test.
Map each package's hot targets (build, typecheck, test, check:exports, lint)
to nx:run-commands under the package.json `nx.targets` block, running the tool
directly (tsc/eslint/tshy/…) with cwd pinned to the project root. The scripts
stay as the source of truth and for `npm run` by humans; nx.json targetDefaults
still supply dependsOn/cache/inputs/outputs. targetDefaults cannot override an
inferred target's executor, so the override lives per package.
Validated from a clean CI-like state (fresh npm ci + nx reset): build,
typecheck, test, check:exports, and lint all pass, and dual ESM/CJS dist
artifacts are produced correctly.
Closes #323
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QEDVnuJAM7zgUUgLNnxn9j
CoverageOverall line coverage: 99.34% across 23 package(s).
|
A single local createNodes plugin cannot replace the per-package nx.targets blocks: verified on nx 23 that workspace plugins load before the built-in package-json inference and last-wins on merge, so a plugin's nx:run-commands targets are clobbered by the built-in nx:run-script inference; and targetDefaults cannot override an inferred target's executor. Only a package's own nx.targets overrides its inferred script targets. Document this so the duplication isn't mistaken for accidental and the plugin dead-end isn't retried. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QEDVnuJAM7zgUUgLNnxn9j
How this flake relates to the npm "empty package.json" bug (npm/cli#8425)Context for readers wondering why the CI error looked like an npm/config problem. The visible error is a generic secondary error. Theory for how CI reaches that abort — a transient version of #8425. Honest uncertainty. For Why this doesn't change the fix. This PR is deliberately trigger-agnostic: running Getting certainty on the exact trigger would mean reproducing with npm at Generated by Claude Code |
What & why
Closes #323.
CI's typecheck/lint/build/test job intermittently fails on a single matrix leg with nx reporting a task failed (e.g.
@composurecdk/eslint-plugin:typecheck) while the same commit passes on every other Node leg. It is not a compiler error — the underlying tool never runs. nx executes package.json script targets through the package manager (itsrun-scriptexecutor spawnsnpm run <script>), and under parallelism annpmstartup intermittently crashes inside npm's own config loader:(Upstream: npm/cli#8425, closed not planned; not fixed by upgrading nx or npm.) See #323 for the full trace.
This maps each package's hot targets —
build,typecheck,test,check:exports,lint— tonx:run-commandsunder thepackage.jsonnx.targetsblock, so nx runs the tool directly (tsc --noEmit,eslint .,tshy, …) withcwdpinned to the project root, eliminating thenpmsubprocess that crashes.Details
package.jsonscriptsare unchanged — they stay the source of truth for each command and keepnpm run <script>working for humans;nx.targetsmirrors them.nx.jsontargetDefaultscontinue to supply each target'sdependsOn/cache/inputs/outputs— the override only swaps the executor from the inferrednx:run-scripttonx:run-commands. Verified thattargetDefaultscannot override an inferred target's executor, which is why the override lives per package.tshyvstsc -p tsconfig.build.jsonforbuild;vitest runvsvitest run --passWithNoTests; packages without abuild/check:exportsscript get no such target).@nx/eslintinference plugin is introduced — thelintoverride still runseslint .at task time and keeps itsdependsOnon@composurecdk/eslint-plugin:build, so the fresh-checkout ordering AGENTS.md describes is unchanged.Validation — clean, CI-like state
Wiped
node_modules,npm ci,nx reset, removed alldist/coverage, then ran the full gate. All green, and dual ESM/CJSdistartifacts are produced correctly:build(run-many)> tshy/tscrun directly (nonpm run)typechecklintcheck:exportstestChecklist
npm run, and npm's config loader crashes under parallelism #323)build,typecheck,test,check:exports,lint, andformat:checkall pass locally from a cleannpm ci+nx resetGenerated by Claude Code