Skip to content

fix(cli): avoid destroying .nuxt while dev runs#1337

Draft
harlan-zw wants to merge 10 commits into
mainfrom
feat/typecheck-reuse-running-dev-types
Draft

fix(cli): avoid destroying .nuxt while dev runs#1337
harlan-zw wants to merge 10 commits into
mainfrom
feat/typecheck-reuse-running-dev-types

Conversation

@harlan-zw

@harlan-zw harlan-zw commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

🔗 Linked issue

❓ Type of change

  • 📖 Documentation
  • 🐞 Bug fix
  • 👌 Enhancement
  • ✨ New feature
  • 🧹 Chore
  • ⚠️ Breaking change

📚 Description

When running multiple agents on the same workspace, they will happily work on top of each other, spinning up multiple dev servers, typechecking, preparing, etc. As these agents run these commands, many of them will delete the .nuxt folder, causing the nitro instance to do a full reload without any clear idea why (per logs).

This in itself isn't a breaking issue, but it causes agents to start diagnosing why the dev server isn't responding as well as being quite annoying for end-users who are trying to test things themselves (unresponsive requests while the rebuild goes through).

To solve this, we port the lock mechanism to dev and change destructive behaviors based on dev servers are running (lock existence). This new lock for dev should also help agents debug the dev server instance themselves if they find it unresponsive (as it surfaces the state and PID).

⚠️ Small scope for regressions if any logic was previously relying on these to work in conjunction, i.e. some modules in how they emit templates/types.

🧭 Behaviour summary

Keyed off the per-process markers in <buildDir>/locks/<pid>.json. Dead/stale markers are taken over silently; clearBuildDir now preserves locks/.

Command Build dir already owned by… Behaviour
nuxt dev a peer dev starts anyway + warns "…reusing the same .nuxt build dir. Run on a separate buildDir…"
nuxt dev a live build refuses
nuxt build any live owner refuses
nuxt typecheck a dev with ready types skips prepare, reuses .nuxt"Reusing types from the running dev server…"
nuxt prepare a dev or build skips the wipe, regenerates in place — "…refreshing templates in place without clearing."

Running `nuxt typecheck` against the same project as a live `nuxt dev`
made typecheck's `writeTypes`+`buildNuxt` wipe `.nuxt/dist`, which the dev
dist-watcher hard-restarts on. With dev and typecheck sharing a buildDir
this produced a restart loop.

`nuxt dev` now writes a `nuxt.lock` *presence* marker (detection only, it no
longer refuses a second dev — multiple dev servers may run concurrently).
`nuxt typecheck` reads it and, when a live `dev` lock owns `<cwd>/.nuxt` and
types already exist, skips its own prepare and type-checks against the
dev-maintained `.nuxt`. No `buildNuxt` -> no `dist` removal -> no restart.

- lockfile: split write (always, unless `NUXT_IGNORE_LOCK`) from enforcement
  (`acquireLock(.., { enforce })`); per-acquisition token so a same-process
  re-acquire (dev reload) isn't clobbered by the prior release; add
  `readActiveLock`. `build` keeps enforcement.
- typecheck: `--prepare` / `--no-prepare` (default auto). `--extends` forces
  prepare in auto mode. Falls back to preparing for custom buildDirs.
@pkg-pr-new

pkg-pr-new Bot commented Jun 9, 2026

Copy link
Copy Markdown
  • nuxt-cli-playground

    npm i https://pkg.pr.new/create-nuxt@1337
    
    npm i https://pkg.pr.new/nuxi@1337
    
    npm i https://pkg.pr.new/@nuxt/cli@1337
    

commit: 1fb8e66

@codspeed-hq

codspeed-hq Bot commented Jun 9, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 2 untouched benchmarks


Comparing feat/typecheck-reuse-running-dev-types (1fb8e66) with main (a3e0a4d)

Open in CodSpeed

harlan-zw added 2 commits June 9, 2026 16:43
… live build

Addresses two adversarial-review findings:

- Typecheck could skip prepare against stale/mid-rebuild `.nuxt`. The dev lock
  is written before `writeTypes`/`buildNuxt`, so a typecheck during dev startup
  or reload could check old generated types. Dev now sets `typesReady` on the
  lock only after the build completes (and clears it while (re)building);
  typecheck reuses `.nuxt` only when `typesReady` is set.
- Dev's detection-only `acquireLock({ enforce: false })` unconditionally
  overwrote any lock, including an active `build` (which mutates the buildDir).
  The non-enforce path now still refuses a live `build` lock; only peer `dev`
  locks are taken over. `updateLock` now merges so partial updates keep `url`.
@harlan-zw harlan-zw changed the title feat(typecheck): reuse a running dev server's prepared types feat(typecheck): skip prepare when a dev server is already running Jun 9, 2026
@harlan-zw harlan-zw marked this pull request as ready for review June 9, 2026 07:48
@harlan-zw harlan-zw requested a review from danielroe as a code owner June 9, 2026 07:48
@harlan-zw harlan-zw changed the title feat(typecheck): skip prepare when a dev server is already running fix(typecheck): skip prepare when a dev server is running Jun 9, 2026
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds per-process lock markers and token-safe lock APIs, updates the dev server to set typesReady:false/true around rebuilds, preserves locks/ when clearing the build dir, and extends nuxt typecheck with a --prepare flag and exported resolvePrepareDecision to skip type generation when a live dev server reports typesReady. Tests exercise lock marker read/prune semantics, acquire/update/release safety, and prepare-decision scenarios.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title 'fix(cli): avoid destroying .nuxt while dev runs' directly addresses the main objective of the PR: preventing the destruction of .nuxt artifacts while dev servers are running.
Description check ✅ Passed The pull request description clearly explains the problem being solved (multiple agents destroying .nuxt folder), the solution (port lock mechanism to dev and change destructive behaviors), and provides a detailed behavior summary table.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/typecheck-reuse-running-dev-types

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
packages/nuxi/src/commands/typecheck.ts (1)

56-58: 💤 Low value

Custom buildDir configurations will always trigger prepare.

The comment acknowledges this limitation, but users with custom buildDir in nuxt.config won't benefit from the optimization. Consider documenting this behavior in the --prepare flag description so users understand why auto-skip may not work for their setup.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/nuxi/src/commands/typecheck.ts` around lines 56 - 58, Update the
help/description for the --prepare flag to document that custom buildDir
settings in nuxt.config will force the command to run prepare because resolving
a custom buildDir requires loading the config (see the buildDir = join(cwd,
'.nuxt') assumption in typecheck command). Specifically, edit the --prepare flag
description in the typecheck command help text to state that auto-skip only
works when the default buildDir is used and that custom buildDir values will
cause prepare to run. Ensure the wording references the prepare behavior and the
buildDir assumption so users understand why auto-skip may not apply.
packages/nuxi/src/utils/lockfile.ts (2)

193-201: 💤 Low value

Spread order preserves caller-supplied token, undermining release safety.

In updateLock, the merge spreads ...info after ...current, so a caller passing token in info would overwrite the original acquisition token. The final token: current?.token line fixes this, but the intermediate spread creates a confusing code path. Consider filtering token from info or documenting that callers must not pass it.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/nuxi/src/utils/lockfile.ts` around lines 193 - 201, The merge in
updateLock creates next by spreading ...current then ...info which allows a
caller-supplied token in info to temporarily override the original token;
although you later set token: current?.token, this is confusing and
unsafe—change the merge to explicitly strip token from the caller-supplied info
(e.g. const { token: _unusedToken, ...safeInfo } = info) and then build next
using ...current, ...safeInfo, pid, startedAt, token: current?.token so callers
cannot override the acquisition token; reference updateLock and the next:
LockInfo creation to locate the change.

217-222: ⚖️ Poor tradeoff

TOCTOU window between reading and unlinking the lock file.

Between readLockFile and tryUnlink, another process could overwrite the lock with a different token. While unlikely in typical usage (same-process re-acquire is the main concern), a concurrent acquireLock from a peer dev server could race here. The current design accepts this since the token check provides best-effort protection. Consider documenting this limitation or using atomic compare-and-delete if stronger guarantees are needed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/nuxi/src/utils/lockfile.ts` around lines 217 - 222, There's a TOCTOU
race between readLockFile(lockPath) and tryUnlink(lockPath) where another
process may replace the lock; either document this limitation near that block or
replace with an atomic compare-and-delete helper (e.g., compareAndUnlink) that
reads the file via fs.promises.open, verifies the token, re-checks file identity
(stat/inode or mtime+size) and only then unlinks, optionally retrying if
identity changed; update usages in the release path (the block using
readLockFile, token, tryUnlink and related acquireLock) to call the new helper
or add a clear comment explaining the best-effort semantics.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/nuxi/src/utils/lockfile.ts`:
- Around line 111-117: fullInfo currently builds token before spreading incoming
info so a caller-supplied token in info can overwrite the generated value;
change the construction of fullInfo (used where token, pid, startedAt and info
are combined) so that ...info is spread first and then token (the generated
`${process.pid}:${++acquireCounter}`) is assigned after the spread, ensuring the
generated token in the variable token (and the increment of acquireCounter)
cannot be overridden by info.

In `@packages/nuxi/test/unit/typecheck-prepare.spec.ts`:
- Around line 96-101: The test "forces a prepare when --extends is passed"
currently writes a lock without typesReady true so it doesn't validate the
override; update the test to write a lock that includes typesReady: true (use
the existing writeLock helper with typesReady: true for buildDir) before calling
resolvePrepareDecision(buildDir, { extends: '../base' }) so the expectation
verifies that resolvePrepareDecision returns { prepare: true } even when types
are already ready; reference the test block containing resolvePrepareDecision,
writeLock, and buildDir to locate and change the lock payload.

---

Nitpick comments:
In `@packages/nuxi/src/commands/typecheck.ts`:
- Around line 56-58: Update the help/description for the --prepare flag to
document that custom buildDir settings in nuxt.config will force the command to
run prepare because resolving a custom buildDir requires loading the config (see
the buildDir = join(cwd, '.nuxt') assumption in typecheck command).
Specifically, edit the --prepare flag description in the typecheck command help
text to state that auto-skip only works when the default buildDir is used and
that custom buildDir values will cause prepare to run. Ensure the wording
references the prepare behavior and the buildDir assumption so users understand
why auto-skip may not apply.

In `@packages/nuxi/src/utils/lockfile.ts`:
- Around line 193-201: The merge in updateLock creates next by spreading
...current then ...info which allows a caller-supplied token in info to
temporarily override the original token; although you later set token:
current?.token, this is confusing and unsafe—change the merge to explicitly
strip token from the caller-supplied info (e.g. const { token: _unusedToken,
...safeInfo } = info) and then build next using ...current, ...safeInfo, pid,
startedAt, token: current?.token so callers cannot override the acquisition
token; reference updateLock and the next: LockInfo creation to locate the
change.
- Around line 217-222: There's a TOCTOU race between readLockFile(lockPath) and
tryUnlink(lockPath) where another process may replace the lock; either document
this limitation near that block or replace with an atomic compare-and-delete
helper (e.g., compareAndUnlink) that reads the file via fs.promises.open,
verifies the token, re-checks file identity (stat/inode or mtime+size) and only
then unlinks, optionally retrying if identity changed; update usages in the
release path (the block using readLockFile, token, tryUnlink and related
acquireLock) to call the new helper or add a clear comment explaining the
best-effort semantics.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 06d36231-913c-426e-8dfd-d0962c0e9cde

📥 Commits

Reviewing files that changed from the base of the PR and between a3e0a4d and 71f030b.

📒 Files selected for processing (6)
  • packages/nuxi/src/commands/typecheck.ts
  • packages/nuxi/src/dev/utils.ts
  • packages/nuxi/src/utils/lockfile.ts
  • packages/nuxi/test/unit/lockfile-presence.spec.ts
  • packages/nuxi/test/unit/lockfile.spec.ts
  • packages/nuxi/test/unit/typecheck-prepare.spec.ts

Comment thread packages/nuxi/src/utils/lockfile.ts
Comment thread packages/nuxi/test/unit/typecheck-prepare.spec.ts Outdated
harlan-zw added 3 commits June 9, 2026 17:57
clearBuildDir() removes every generated artifact before buildNuxt
rewrites them. When a dev server is live its watcher reloads into that
gap and resolves aliases (e.g. drizzle #schema/<n>) against a
momentarily-absent file, throwing ENOENT; wiping under a running build
is equally destructive. buildNuxt regenerates all templates in place
(content-diffed) regardless, so reuse is safe and still hands callers
like db:generate fresh artifacts. Stop the owning process when a clean
wipe is genuinely needed.
The single shared nuxt.lock cannot represent more than one owner. When
peer dev servers share a buildDir (e.g. parallel agents): acquire
clobbered the prior record, updateLock no-op'd for every non-owner
(current.pid !== process.pid), and whichever server exited first
unlinked the file out from under the others — making a still-live dev
server invisible so typecheck/prepare would rebuild/wipe under it.

Move presence markers to one-file-per-process under <buildDir>/locks/
<pid>.json. Each process only ever writes or removes its own path, so
reads enumerate the directory and the three hazards disappear.
readActiveLocks() returns every live owner (pruning dead/stale files on
read); readActiveLock() keeps the single-owner shape (build wins, else
newest dev). typecheck now reuses types from any ready dev peer, and
clearBuildDir preserves locks/ so a wipe can't race-delete a fresh
marker.
@harlan-zw harlan-zw changed the title fix(typecheck): skip prepare when a dev server is running fix(cli): avoid destroying .nuxt while dev servers run Jun 10, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/nuxi/src/utils/lockfile.ts`:
- Around line 190-198: acquireLock currently does a non-atomic read-then-write
(readActiveLocks -> writeFileSync) which allows a race; change to an
atomic-create first approach: attempt to atomically create the lock file (use
fs.openSync(lockPath, 'wx') or equivalent) and write JSON there; if the create
fails with EEXIST, then call readActiveLocks() and apply the existing blocker
logic (enforce vs command==='build'); if the existing lock belongs to this
process/token then allow overwrite (use writeFileSync) and return
makeRelease(lockPath, token); keep makeRelease and fullInfo usage but ensure the
initial write is atomic so two processes cannot both succeed. Ensure EEXIST
handling maps to the same return shapes ({ existing } or { release }).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 84e657b1-26ff-402c-be96-d5495ff6eec3

📥 Commits

Reviewing files that changed from the base of the PR and between 46b032c and de908a9.

📒 Files selected for processing (7)
  • packages/nuxi/src/commands/prepare.ts
  • packages/nuxi/src/commands/typecheck.ts
  • packages/nuxi/src/utils/fs.ts
  • packages/nuxi/src/utils/lockfile.ts
  • packages/nuxi/test/unit/lockfile-presence.spec.ts
  • packages/nuxi/test/unit/lockfile.spec.ts
  • packages/nuxi/test/unit/typecheck-prepare.spec.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/nuxi/src/commands/typecheck.ts
  • packages/nuxi/test/unit/typecheck-prepare.spec.ts

Comment thread packages/nuxi/src/utils/lockfile.ts Outdated
Two dev servers sharing a buildDir coexist (the lock is detection-only
for dev), but they write and watch the same .nuxt — concurrent rebuilds
can trigger conflicting reloads. acquireLock now reports the live peers
it coexists with, and dev warns when one is already running so the user
knows the build dir is shared (and can isolate with a separate buildDir).

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/nuxi/src/utils/lockfile.ts (1)

27-29: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Don't expire a live owner just because the marker is old.

isLockActive() returns false once startedAt is older than 24 hours even if the PID is still alive, and readActiveLocks() then prunes that marker. Any long-lived dev/build process stops protecting its buildDir after a day, which reopens the .nuxt wipe/race this lock is meant to prevent. This needs a heartbeat or a real process-start check rather than a hard TTL on live PIDs.

Also applies to: 71-76

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/nuxi/src/utils/lockfile.ts` around lines 27 - 29, isLockActive() and
readActiveLocks currently expire locks solely by MAX_LOCK_AGE_MS which allows
live long-running processes to be pruned; change the logic so that before
treating a lock as stale you verify the owner process is not actually running
(e.g., a processExists check using the stored PID) and only prune markers when
the PID is dead AND startedAt is older than MAX_LOCK_AGE_MS; update
isLockActive, readActiveLocks and any helper that uses startedAt/PID to first
try a live-process check (or fallback to TTL if liveness cannot be determined)
instead of relying on the hard TTL alone.
♻️ Duplicate comments (1)
packages/nuxi/src/utils/lockfile.ts (1)

183-193: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Make exclusive acquisition atomic.

acquireLock() still does a read-then-write on the marker set. Two enforced callers can both observe others as empty and both return { release }, so they proceed as simultaneous "exclusive" owners and can mutate the same buildDir concurrently. The per-PID JSON files are fine for discovery, but exclusivity needs one atomic ownership gate that both build acquisition and conflict detection consult.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/nuxi/src/utils/lockfile.ts` around lines 183 - 193, acquireLock
currently does a read-then-write race (readActiveLocks -> writeFileSync) so two
enforce callers can both see no blockers and both become "exclusive"; fix by
introducing an atomic ownership gate before writing fullInfo: attempt to create
a dedicated atomic owner marker (e.g. open/create lockPath.owner or lockPath +
'.claim' with exclusive create semantics like fs.open with O_EXCL/'wx'); if the
exclusive create fails, readActiveLocks again and return the existing blocker,
otherwise writeFileSync(fullInfo) and return { release: makeRelease(lockPath,
token), peers: others }; update acquireLock to consult this new atomic create
step (and clean it up in makeRelease) so exclusivity is enforced even under
concurrent processes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/nuxi/src/utils/lockfile.ts`:
- Around line 192-193: The current in-place JSON writes (e.g.,
writeFileSync(lockPath, JSON.stringify(fullInfo, null, 2)) used when acquiring
locks and in updateLock()) can race with concurrent
readActiveLocks()/readLockFile() and produce transient missing-owner reads;
change those writes to atomic replace: write the JSON to a temp file in the same
directory and then atomically rename/move it to lockPath (ensuring fsync of the
temp file and directory if available), and apply the same change for the other
occurrence around lines 223-224 so all lock file updates use the
temp-file-then-rename pattern to avoid truncate/write windows.

---

Outside diff comments:
In `@packages/nuxi/src/utils/lockfile.ts`:
- Around line 27-29: isLockActive() and readActiveLocks currently expire locks
solely by MAX_LOCK_AGE_MS which allows live long-running processes to be pruned;
change the logic so that before treating a lock as stale you verify the owner
process is not actually running (e.g., a processExists check using the stored
PID) and only prune markers when the PID is dead AND startedAt is older than
MAX_LOCK_AGE_MS; update isLockActive, readActiveLocks and any helper that uses
startedAt/PID to first try a live-process check (or fallback to TTL if liveness
cannot be determined) instead of relying on the hard TTL alone.

---

Duplicate comments:
In `@packages/nuxi/src/utils/lockfile.ts`:
- Around line 183-193: acquireLock currently does a read-then-write race
(readActiveLocks -> writeFileSync) so two enforce callers can both see no
blockers and both become "exclusive"; fix by introducing an atomic ownership
gate before writing fullInfo: attempt to create a dedicated atomic owner marker
(e.g. open/create lockPath.owner or lockPath + '.claim' with exclusive create
semantics like fs.open with O_EXCL/'wx'); if the exclusive create fails,
readActiveLocks again and return the existing blocker, otherwise
writeFileSync(fullInfo) and return { release: makeRelease(lockPath, token),
peers: others }; update acquireLock to consult this new atomic create step (and
clean it up in makeRelease) so exclusivity is enforced even under concurrent
processes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 625dece2-06ee-4f44-8976-53bd1cb03705

📥 Commits

Reviewing files that changed from the base of the PR and between 3861166 and 43f53a8.

📒 Files selected for processing (3)
  • packages/nuxi/src/dev/utils.ts
  • packages/nuxi/src/utils/lockfile.ts
  • packages/nuxi/test/unit/lockfile.spec.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/nuxi/src/dev/utils.ts

Comment thread packages/nuxi/src/utils/lockfile.ts Outdated
@harlan-zw harlan-zw changed the title fix(cli): avoid destroying .nuxt while dev servers run fix(cli): avoid destroying .nuxt while dev runs Jun 10, 2026
Addresses CodeRabbit review:
- Major: in-place writeFileSync truncates then writes, so a concurrent
  readActiveLocks could land in the window and see the owner vanish.
  Per-process marker writes + updateLock now write a sibling temp and
  rename over the target (atomic replace).
- Critical: the per-PID redesign lost the build-vs-build mutex the old
  single-file 'wx' gave — two 'nuxt build' could both pass the advisory
  read then both write their own marker. A build now claims a shared
  'build.lock' sentinel via an atomic linkSync-from-temp (create-if-
  absent against an already-populated inode); the loser gets the live
  winner back, a stale sentinel is taken over. readActiveLocks reads all
  non-.tmp markers so the sentinel is still discoverable.
@harlan-zw harlan-zw marked this pull request as draft June 12, 2026 09:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant