Skip to content

fix(dev): stabilize Utoopack HMR and file watching - #80

Merged
xusd320 merged 1 commit into
mainfrom
xusd320/fix-utoopack-hmr-dev-watcher
Aug 6, 2026
Merged

fix(dev): stabilize Utoopack HMR and file watching#80
xusd320 merged 1 commit into
mainfrom
xusd320/fix-utoopack-hmr-dev-watcher

Conversation

@xusd320

@xusd320 xusd320 commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Fix Utoopack development HMR instability by removing EVJS-driven generated-entry timestamp invalidation and the stats-version completion barrier.
  • Keep Utoopack responsible for watching generated .ev inputs while EVJS relinks topology-preserving framework artifacts from the last published build facts.
  • Harden the existing EVJS watcher implementation without adding a third-party watcher dependency.
  • Fixes bug(utoopack): client source edits terminate ev dev after EMFILE watcher fallback #79.

Changes

  • Rework Utoopack artifact-only plan transitions to reuse published build facts and preserve server-stats observations across accepted transitions.
  • Remove worker-side .ev timestamp touching and stats-version polling as an EVJS update barrier.
  • Canonicalize dependency ordering to avoid unnecessary watcher-generation replacement and transient file-descriptor spikes.
  • Fall back to polling when native watchers exhaust resources, are unsupported, or close unexpectedly; start directly in polling mode under the macOS Codex Seatbelt sandbox.
  • Add per-target polling backoff for resource errors while keeping healthy targets responsive.
  • Recover from atomic symlink replacement races where readlink observes EINVAL.
  • Add regression coverage for Utoopack transitions, watcher fallback, polling recovery, and watcher handoff behavior.

Validation

  • npm run check-types
  • npm run lint
  • npm test — 17/17 tasks passed; @evjs/ev 813/813 tests; @evjs/bundler-utoopack 87/87 tests
  • npx vitest run tests/commands.test.ts — 241/241 tests
  • git diff --check

Risk / rollout

  • Development-only behavior; no public configuration or runtime API changes.
  • stats.json remains a source of normal server build facts, but it is no longer used as an EVJS plan-transition completion barrier.
  • Polling remains a fallback and applies exponential backoff only to resource-limited targets; healthy targets retain the existing interval.

Reviewer notes

  • Please focus on the Utoopack transition/facts ownership in packages/bundler-utoopack/src/adapter/index.ts.
  • The watcher changes intentionally remain inside EVJS's existing implementation and do not introduce Watchpack or another dependency.

Summary by CodeRabbit

  • New Features

    • Development watch mode now automatically uses polling in macOS Seatbelt environments.
    • Watch mode recovers more reliably when native file watching stops or encounters resource limits.
    • Development builds handle artifact-only updates more efficiently while preserving published build information.
  • Bug Fixes

    • Improved handling of filesystem races, missing paths, invalid links, and watcher failures.
    • Prevented rolled-back development changes from affecting later server statistics.

Let Utoopack observe generated .ev changes directly and reuse published facts for topology-preserving artifact relinks. Harden framework watcher fallback, polling backoff, and symlink replacement recovery.
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 31340fa0-8601-4e84-82ae-c4de82808c61

📥 Commits

Reviewing files that changed from the base of the PR and between b766b3d and e4da9ec.

📒 Files selected for processing (8)
  • packages/bundler-utoopack/src/adapter/dev-worker-client.ts
  • packages/bundler-utoopack/src/adapter/index.ts
  • packages/bundler-utoopack/tests/adapter.test.ts
  • packages/ev/src/_internal/build/bundler.ts
  • packages/ev/src/_internal/build/commands.ts
  • packages/ev/src/_internal/build/dev-watch.ts
  • packages/ev/tests/commands.test.ts
  • packages/ev/tests/dev-watch.test.ts

📝 Walkthrough

Walkthrough

The PR changes Utoopack development publication to reuse published build facts during artifact-only transitions. It also adds macOS Seatbelt polling selection, bounded polling retries, native watcher recovery, and symlink topology-race handling.

Changes

Utoopack publication lifecycle

Layer / File(s) Summary
Published facts and publication contract
packages/bundler-utoopack/src/adapter/dev-worker-client.ts, packages/bundler-utoopack/src/adapter/index.ts, packages/ev/src/_internal/build/bundler.ts
The worker handle no longer exposes filesystem invalidation. The adapter records published build facts and server stats versions. Development lifecycle documentation permits reuse of valid published facts.
Artifact transitions and deferred statistics
packages/bundler-utoopack/src/adapter/index.ts
Plan updates and rollbacks regenerate framework artifacts from published facts. Deferred server-stat observations are retried after accepted transitions and discarded after rollback.
Publication transition validation
packages/bundler-utoopack/tests/adapter.test.ts
Tests cover relinking with stale compiler statistics, delayed server statistics, accepted transitions, and rollback behavior.

Development watcher recovery

Layer / File(s) Summary
Initial mode and polling recovery
packages/ev/src/_internal/build/commands.ts, packages/ev/src/_internal/build/dev-watch.ts
Development watch mode selects polling for macOS Seatbelt environments. Polling normalizes watch plans and applies bounded retries for resource-limited reads.
Native fallback and topology races
packages/ev/src/_internal/build/dev-watch.ts
Native watcher unavailability and unexpected closure trigger polling recovery. Symlink reads tolerate missing-path and invalid-link races.
Watcher mode and recovery validation
packages/ev/tests/commands.test.ts, packages/ev/tests/dev-watch.test.ts
Tests cover Seatbelt polling, watcher fallback, resource backoff, setup races, unexpected closure, symlink replacement, and controlled watcher cleanup.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related issues

Possibly related PRs

  • afx-team/evjs#42 — Both modify development watch lifecycle behavior in commands.ts.
  • afx-team/evjs#64 — Both modify Utoopack plan transitions, publication, and build-facts handling.

Suggested reviewers: fireairforce

✨ 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 xusd320/fix-utoopack-hmr-dev-watcher

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.

@xusd320
xusd320 marked this pull request as ready for review August 6, 2026 02:12
@xusd320
xusd320 merged commit 701f352 into main Aug 6, 2026
2 checks passed
@xusd320
xusd320 deleted the xusd320/fix-utoopack-hmr-dev-watcher branch August 6, 2026 02:17

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e4da9ece8d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

const { facts, serverStatsVersion } =
await this.collectFinalBuildFacts(plan);
): () => Promise<void> {
const facts = this.publishedFacts;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Relink generated updates from fresh client facts

When a generated client module changes its imports—for example, an existing plugin module starts importing a stylesheet—the BuildPlan can remain artifact-only while Utoopack's entrypoint asset inventory gains main.css. This path always republishes the cached facts from before the generated-input rebuild, so the regenerated HTML and manifest omit that asset; client-only sessions have no stats monitor to correct them, and mixed sessions can also read server stats before the client rebuild finishes. Wait for fresh client stats or monitor and relink after the client compile instead of treating topology preservation as asset preservation.

AGENTS.md reference: AGENTS.md:L42-L43

Useful? React with 👍 / 👎.

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.

bug(utoopack): client source edits terminate ev dev after EMFILE watcher fallback

1 participant