EPBDS-16211 fix watch-lib: same config as the published build - #49
Merged
Merged
Conversation
`watch-lib` had its own webpack config, and it had drifted. Measured against
`build-lib` rather than read:
dist/*.d.ts build-lib: 2 watch-lib: 0
stylesheet build-lib: dist/static/all.css
watch-lib: dist/static/ui-render.css
font.css, the semantic stub, the root-static re-exports: build-lib only
All three matter for the one thing `watch-lib` exists for — a consumer
`yalc`-linking the package to try a pre-release. They would get a stylesheet at a
path the README and the published package do not use, no types at all, and a
root `static/` left over from an earlier `build-lib` that watch never refreshes:
correct-looking and silently stale.
THE TYPES WERE THE SUBTLE ONE. Both configs set `output.clean: true`; `build-lib`
gets away with it because `gen-ts` runs immediately after webpack. In watch mode
nothing regenerates them, so every rebuild wiped the declarations a previous
`build-lib` had produced.
FIXED BY DELETING THE DUPLICATE, not by syncing it. `webpack.watch.config.mjs` is
gone and `watch-lib` uses `webpack.library.config.mjs`, which was already
watch-aware — it taps `watchRun` as well as `beforeRun`. Two supporting changes:
`output.clean` becomes `{ keep: /\.d\.ts$/ }` so declarations survive a rebuild
(a no-op for `build-lib`, where `gen-ts` rewrites them anyway), and `watch-lib`
runs `gen-ts` once before starting the watcher.
Verified the way the divergence was found: after the change, `watch-lib` produces
an IDENTICAL file list to `build-lib` — 8 files, 2 `.d.ts`, the stylesheet at
`dist/static/all.css` re-exporting the root copy — and the published CSS keeps
its sha256.
ALSO FIXES A READ-AFTER-CHECK RACE that has been producing intermittent failures
all day. `css.pipeline.parity.test.js` tested `existsSync` at module load and
`readFileSync` in a `beforeAll`; something empties the root `static/` directory
between those moments in a full-suite run, so the describe was not skipped and
three tests died on ENOENT — invisible in an isolated run, and it reads like a
broken assertion rather than a missing file. The file is now read once, at load,
so the suite either has the bytes it checked for or skips.
What is established about the emptying, and what is not, is written into that
file rather than guessed: it is reliably triggered by the LESS render in
`css.semantic-parity.test.js` (bisected suite by suite, then by disabling that
suite's compile), and it is NOT done through `fs` in the jest process — probes
around `rmSync`/`unlinkSync`/`rmdirSync`/`renameSync` and their async and
`fs.promises` forms, installed both in `setupFiles` and inside the suite, never
fire, and no watcher process is running. The mechanism is unexplained. CI is
unaffected either way: it runs jest before `build-lib`, so those three always
skip there.
Gates: jsdom 167 suites / 2540 tests on React 16.14, 17 and 18.3; Chrome 41/41;
`lint:js`, `lint:css`, `css:fixture:check`, both docs checks, `build-lib` and
`build-css` green; published CSS byte-identical.
AlexSamBY
added a commit
that referenced
this pull request
Sep 15, 2026
The fix landed in #49; the plan still described it as open in three places. R15 item 8, F1 step 5's "still open" list and H7 now say what is true: `webpack.watch.config.mjs` is deleted, `watch-lib` runs the library config itself, and H7 has two configs to unify rather than three. Step 5's note also records what fixing watch surfaced — `CleanRootStatic` tapping `watchRun`, so any source write emptied the root `static/` for the length of a rebuild. It cost an afternoon and reads as flakiness, so it is written down where the next person will look.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
watch-libhad its own webpack config, and it had drifted. Measured againstbuild-librather than read:build-libwatch-lib(before)dist/*.d.tsdist/static/all.cssdist/static/ui-render.cssfont.css, semantic stub, root-static re-exportsAll three matter for the one thing
watch-libexists for — a consumeryalc-linking the package to try a pre-release. They would get a stylesheet at a path neither the README nor the published package uses, no types at all, and a rootstatic/left over from an earlierbuild-libthat watch never refreshes: correct-looking and silently stale.The types were the subtle one. Both configs set
output.clean: true;build-libgets away with it becausegen-tsruns immediately after webpack. In watch mode nothing regenerates them, so every rebuild wiped the declarations a previousbuild-libhad produced.Fixed by deleting the duplicate, not by syncing it
webpack.watch.config.mjsis gone andwatch-libuseswebpack.library.config.mjs— which was already watch-aware, tappingwatchRunas well asbeforeRun. Two supporting changes:output.cleanbecomes{ keep: /\.d\.ts$/ }so declarations survive a rebuild (a no-op forbuild-lib, wheregen-tsrewrites them anyway), andwatch-librunsgen-tsonce before starting the watcher.Verified the way the divergence was found: afterwards
watch-libproduces an identical file list tobuild-lib— 8 files, 2.d.ts, stylesheet atdist/static/all.cssre-exporting the root copy — and the published CSS keeps its sha256.Also fixes a read-after-check race behind today's intermittent failures
css.pipeline.parity.test.jstestedexistsSyncat module load andreadFileSyncin abeforeAll. Something empties the rootstatic/directory between those moments in a full-suite run, so the describe was not skipped and three tests died onENOENT— invisible in an isolated run, and it reads like a broken assertion rather than a missing file. The file is now read once, at load: the suite either has the bytes it checked for, or it skips.What is established about the emptying, and what is not, is written into that file rather than guessed:
css.semantic-parity.test.js— bisected suite by suite, then by disabling that suite's compile (off: the directory survives; on: emptied every time);fsin the jest process — probes aroundrmSync/unlinkSync/rmdirSync/renameSyncand their async andfs.promisesforms, installed both insetupFilesand inside the suite itself, never fire, and no watcher process is running.The mechanism is unexplained and left recorded rather than papered over. CI is unaffected either way: it runs jest before
build-lib, so those three always skip there — which is what the describe name says.Gates
jsdom 167 suites / 2540 tests on React 16.14, 17 and 18.3; Chrome 41/41;
lint:js,lint:css,css:fixture:check, both docs checks,build-libandbuild-cssgreen; published CSS byte-identical.🤖 Generated with Claude Code