Motivation
PR #1612 surfaced a runtime regression that no existing check caught: the browser's RemoteOAuthStorage transitively value-imported the Node-only store-io.js (atomically → stubborn-fs → node:process.getuid), which pulled Node built-ins into the browser bundle and crashed the web app to a blank page at runtime.
It slipped through because:
- Unit/integration tests run in node / happy-dom, never a real browser bundle.
smoke:web only asserts GET / serves the SPA HTML with the injected token — it never executes the React app.
The PR added a source-level guard (oauth-persist-browser-safe.test.ts) that scans the browser-reachable OAuth-storage modules for forbidden imports. That closes this hole, but a static/enumerated source scan can't catch the general category — a Node dep pulled in through a module not on the list, or via a dependency, would still ship a broken bundle.
Proposal
Add a CI step that actually boots the built web client in a headless browser (Playwright chromium is already available for the Storybook tests) and asserts the app renders its first meaningful frame (e.g. the "Add Servers" control) with no uncaught page errors (in particular no Module "node:*" has been externalized for browser compatibility errors).
This would catch any "Node code reached the browser bundle" regression as a class, not one import at a time.
Notes
- Keep it lightweight — a boot/render assertion, not a full interaction suite (that's what the Playwright e2e in the PR already demonstrated ad hoc).
- Consider wiring it into
npm run ci alongside the existing smokes.
Discovered during the browser smoke test of #1612.
Motivation
PR #1612 surfaced a runtime regression that no existing check caught: the browser's
RemoteOAuthStoragetransitively value-imported the Node-onlystore-io.js(atomically→stubborn-fs→node:process.getuid), which pulled Node built-ins into the browser bundle and crashed the web app to a blank page at runtime.It slipped through because:
smoke:webonly assertsGET /serves the SPA HTML with the injected token — it never executes the React app.The PR added a source-level guard (
oauth-persist-browser-safe.test.ts) that scans the browser-reachable OAuth-storage modules for forbidden imports. That closes this hole, but a static/enumerated source scan can't catch the general category — a Node dep pulled in through a module not on the list, or via a dependency, would still ship a broken bundle.Proposal
Add a CI step that actually boots the built web client in a headless browser (Playwright chromium is already available for the Storybook tests) and asserts the app renders its first meaningful frame (e.g. the "Add Servers" control) with no uncaught page errors (in particular no
Module "node:*" has been externalized for browser compatibilityerrors).This would catch any "Node code reached the browser bundle" regression as a class, not one import at a time.
Notes
npm run cialongside the existing smokes.Discovered during the browser smoke test of #1612.