Skip to content

fix(build): debounce webpack watch mode to avoid mid-write reads (#78) - #82

Open
MonaAghili wants to merge 1 commit into
mainfrom
fix/webpack-watch-aggregate-timeout
Open

fix(build): debounce webpack watch mode to avoid mid-write reads (#78)#82
MonaAghili wants to merge 1 commit into
mainfrom
fix/webpack-watch-aggregate-timeout

Conversation

@MonaAghili

Copy link
Copy Markdown
Contributor

Summary

  • Fixes webpack watch mode intermittently reads sdkjs source mid-write, breaking the concatenated bundle and increasing build times #78: npm run watch:cell (and watch:word/watch:slide/watch:visio) could intermittently produce a truncated sdk-all.js (<1KB) with a Module parse failed error, immediately followed by a correct rebuild.
  • Root cause: webpack's default watchOptions.aggregateTimeout is 20ms (confirmed in the installed webpack@5.108.4 source). Editors can flush a single save as multiple MODIFY/rename events, especially over a WSL2/9p filesystem boundary. If a rebuild starts inside that 20ms window, sdk-concat.cjs re-reads the file mid-write and concatenates a truncated fragment into the ~400+ file bundle, producing a syntax error at the tail of the generated module.
  • Fix: set watchOptions.aggregateTimeout to 500 in chunkConfig() in build/webpack.sdk.factory.mjs, shared by all four SDK targets (word/cell/slide/visio) and both chunk variants (min/all). watchOptions is a documented no-op for one-shot builds, so npm run build / CI are unaffected.
  • Added WATCH_AGGREGATE_TIMEOUT env override for tuning on a given machine/CI watcher, consistent with this file's other env-tunable knobs. Invalid input (non-numeric/negative) warns and falls back to the default instead of throwing, so a stray/typo'd env var can never break a plain build.

Why 500ms

25x webpack's default, comfortably absorbing a multi-event editor flush, while staying small relative to this pipeline's warm incremental rebuild time (~5-8s dev). It's a debounce on the rebuild trigger, not a read-time stability check — sdk-concat.cjs still does a plain readFile once the timeout fires, so this narrows the race window rather than eliminating it structurally. A write that's still landing after 500ms of silence (very slow disk, network mount) could theoretically still race; a full fix would require content-stability polling or retry-on-parse-failure in the loader, which is out of scope for this issue.

Testing

  • npm test --prefix build: 45/45 passing, including new coverage for:
    • default aggregateTimeout (500) on both chunks, all targets share the one factory
    • WATCH_AGGREGATE_TIMEOUT override, including 0 (explicitly honored, not treated as unset)
    • invalid override input warns and falls back rather than throwing, verified via sdkConfig() itself (not just the parsing helper)
  • Live repro: ran npm run watch:cell-equivalent, then rewrote a config-listed source file in two staggered chunks (5-10ms apart) to simulate a multi-event editor save. Before the fix this pattern reliably races; with it, exactly one rebuild fired and the resulting sdk-all-min.js was full-size and passed node --check.
  • Full production build of the cell module confirmed unaffected: sdk-all.js emitted at expected size (~19.8 MiB minified).

Not in scope

Close #78

Signed-off-by: Mona Aghili <mona.laghili@gmail.com>
@MonaAghili
MonaAghili requested a review from a team as a code owner August 27, 2026 11:04
@MonaAghili
MonaAghili requested review from a user, j-base64 and moodyjmz and removed request for a team August 27, 2026 11:04
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.

webpack watch mode intermittently reads sdkjs source mid-write, breaking the concatenated bundle and increasing build times

1 participant