Skip to content

fix(FR-2157): prevent double rebuild on config.toml change#5749

Merged
graphite-app[bot] merged 1 commit intomainfrom
fix/FR-2157-prevent-double-rebuild
Mar 10, 2026
Merged

fix(FR-2157): prevent double rebuild on config.toml change#5749
graphite-app[bot] merged 1 commit intomainfrom
fix/FR-2157-prevent-double-rebuild

Conversation

@nowgnuesLee
Copy link
Copy Markdown
Contributor

@nowgnuesLee nowgnuesLee commented Mar 5, 2026

Resolves #5621 (FR-2157)

Summary

When config.toml is modified during development, the browser was reloading twice instead of once. This was caused by two independent mechanisms both triggering reloads:

  1. webpack context dependency: When webpack resolves aliases outside react/ (e.g. backend.ai-client-esm../dist/lib/...), enhanced-resolve walks up the directory tree and adds the project root as a context dependency. This causes webpack to detect config.toml changes → recompile → HMR finds no module updates → falls back to full page reload.

  2. fs.watch dying on atomic save: IDEs like VS Code use atomic save (write temp → rename), which replaces the file's inode. fs.watch watches the old inode and stops detecting changes, leaving only the webpack-triggered reload (which itself fires twice due to temp file + rename events).

Changes

  • watchOptions.ignored: string array → RegExp — Ignore all files directly in the project root ([^/]+$ pattern) to catch both config files AND editor temp files. dist/ and packages/ subdirectories remain watched for HMR.
  • fs.watchfs.watchFile for individual files — Polling-based watching (500ms interval) survives file replacements from atomic save. Directories (resources/i18n) still use fs.watch.
  • Shared debounce timer (300ms) — All watchers share a single timer to coalesce rapid events into one reload signal.

Verification

scripts/verify.sh: ALL PASS (Relay, Lint, Format, TypeScript)

Tested with Chrome DevTools monitoring:

  • Server sends exactly 1 static-changed WebSocket message per config.toml edit
  • webpack does NOT recompile (no "Compiling..." in terminal)
  • Browser reloads exactly once

Test plan

  • Run dev server and modify config.toml from IDE — verify only ONE reload occurs
  • Verify HMR still works for React source changes
  • Verify dist/lib/backend.ai-client-esm.js changes still trigger HMR
  • Verify index.html changes still trigger a page reload
  • Verify i18n translation file changes still trigger a page reload
  • Verify resources/theme.json changes still trigger a page reload
  • Production build (pnpm run build) completes successfully

🤖 Generated with Claude Code

@github-actions github-actions Bot added the size:S 10~30 LoC label Mar 5, 2026
Copy link
Copy Markdown
Contributor Author

nowgnuesLee commented Mar 5, 2026


How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • flow:merge-queue - adds this PR to the back of the merge queue
  • flow:hotfix - for urgent changes, fast-track this PR to the front of the merge queue

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has required the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@nowgnuesLee nowgnuesLee force-pushed the fix/FR-2157-prevent-double-rebuild branch from 99024cd to 872f52c Compare March 6, 2026 04:02
@github-actions github-actions Bot added comp:DevServer lit-cleanup size:M 30~100 LoC and removed size:S 10~30 LoC labels Mar 6, 2026
@nowgnuesLee nowgnuesLee marked this pull request as ready for review March 6, 2026 06:19
@nowgnuesLee nowgnuesLee requested review from Copilot and removed request for Copilot March 6, 2026 06:19
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adjusts the React dev-server / webpack watcher configuration to stop config.toml edits from triggering redundant rebuild + reload cycles during development, especially with editors that use atomic-save semantics.

Changes:

  • Consolidates dev-server reload signaling behind a shared debounce to coalesce rapid watcher events.
  • Switches per-file watching from fs.watch to fs.watchFile (polling) to survive atomic-save inode replacement.
  • Replaces watchOptions.ignored string-array configuration with a single RegExp intended to ignore project-root files (and temp files) to prevent webpack rebuilds.

Comment thread react/craco.config.cjs Outdated
Comment thread react/craco.config.cjs Outdated
@nowgnuesLee nowgnuesLee force-pushed the fix/FR-2157-prevent-double-rebuild branch from 872f52c to 80b6a20 Compare March 6, 2026 06:28
Copy link
Copy Markdown
Member

@yomybaby yomybaby left a comment

Choose a reason for hiding this comment

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

LGTM

@graphite-app
Copy link
Copy Markdown

graphite-app Bot commented Mar 10, 2026

Merge activity

Resolves #5621 ([FR-2157](https://lablup.atlassian.net/browse/FR-2157))

## Summary

When `config.toml` is modified during development, the browser was reloading **twice** instead of once. This was caused by two independent mechanisms both triggering reloads:

1. **webpack context dependency**: When webpack resolves aliases outside `react/` (e.g. `backend.ai-client-esm` → `../dist/lib/...`), `enhanced-resolve` walks up the directory tree and adds the project root as a context dependency. This causes webpack to detect `config.toml` changes → recompile → HMR finds no module updates → falls back to full page reload.

2. **`fs.watch` dying on atomic save**: IDEs like VS Code use atomic save (write temp → rename), which replaces the file's inode. `fs.watch` watches the old inode and stops detecting changes, leaving only the webpack-triggered reload (which itself fires twice due to temp file + rename events).

### Changes

- **`watchOptions.ignored`: string array → RegExp** — Ignore all files directly in the project root (`[^/]+$` pattern) to catch both config files AND editor temp files. `dist/` and `packages/` subdirectories remain watched for HMR.
- **`fs.watch` → `fs.watchFile` for individual files** — Polling-based watching (500ms interval) survives file replacements from atomic save. Directories (`resources/i18n`) still use `fs.watch`.
- **Shared debounce timer (300ms)** — All watchers share a single timer to coalesce rapid events into one reload signal.

## Verification
`scripts/verify.sh`: ALL PASS (Relay, Lint, Format, TypeScript)

Tested with Chrome DevTools monitoring:
- Server sends exactly 1 `static-changed` WebSocket message per config.toml edit
- webpack does NOT recompile (no "Compiling..." in terminal)
- Browser reloads exactly once

## Test plan
- [x] Run dev server and modify `config.toml` from IDE — verify only ONE reload occurs
- [ ] Verify HMR still works for React source changes
- [ ] Verify `dist/lib/backend.ai-client-esm.js` changes still trigger HMR
- [ ] Verify `index.html` changes still trigger a page reload
- [ ] Verify i18n translation file changes still trigger a page reload
- [ ] Verify `resources/theme.json` changes still trigger a page reload
- [ ] Production build (`pnpm run build`) completes successfully

🤖 Generated with [Claude Code](https://claude.com/claude-code)

[FR-2157]: https://lablup.atlassian.net/browse/FR-2157?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
@graphite-app graphite-app Bot force-pushed the fix/FR-2157-prevent-double-rebuild branch from 80b6a20 to 6927758 Compare March 10, 2026 05:38
@graphite-app graphite-app Bot merged commit 6927758 into main Mar 10, 2026
7 checks passed
@graphite-app graphite-app Bot deleted the fix/FR-2157-prevent-double-rebuild branch March 10, 2026 05:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

React dev server triggers double rebuild on config.toml change

3 participants