feat: Add off mode to UI5_WATCH_MODE - #1565
RandomByte wants to merge 3 commits into
Conversation
ce6fc6d to
da7da79
Compare
In CI and other environments where sources do not change while the server
runs, file watching adds cost without benefit. The polling backend is the most
expensive: it walks the source tree every 250 ms, and it is the default inside
containers, where CI commonly runs.
UI5_WATCH_MODE=off makes the fileWatcher facade's subscribe() return an inert
subscription: the callback is never invoked and unsubscribe() is a no-op, so no
backend is loaded and no filesystem is polled. All three watcher consumers
(WatchHandler, ProjectDefinitionWatcher, projectGraphSettleWatcher) go through
this facade, so none of them starts an OS watch handle or a poll loop. Source
changes no longer trigger rebuilds or live reload while the server runs.
The backend decision memoizes a mode string ("native" | "polling" | "off")
instead of a boolean. shouldUsePolling() and the new isWatchingDisabled()
derive from it. The "off" selection is logged at verbose, consistent with the
polling and native modes.
Expose fileWatcher through the package's internal exports so @ui5/cli can
import isWatchingDisabled(), matching the ./internal/... export pattern the CLI
already uses for ProjectDefinitionWatcher.
JIRA: CPOUI5FOUNDATION-1355
Live reload needs a watcher to learn when to push a reload, so it cannot work in "off" mode. `ui5 serve` now resolves liveReload from all three sources (default, --live-reload, server.settings.liveReload) and then, when watching is disabled, forces it off regardless of how it was enabled. With liveReload false the server skips minting the WebSocket token and calling attachLiveReloadServer(), so no live-reload WebSocket server is attached and no server-side change is needed. isWatchingDisabled() is imported dynamically inside the handler, matching how the command already loads its other @ui5/project and @ui5/server dependencies. On startup in "off" mode the handler logs that file watching is disabled and that resources still build on demand but changes are not picked up while the server runs. When live reload was enabled, it additionally logs that live reload has been disabled because it requires a watcher.
Add a Troubleshooting section pointing CI users at UI5_WATCH_MODE=off, next to the existing polling/native guidance. It states what "off" removes (rebuilding on change and live reload), what it keeps (building resources on demand), and that sources and configuration must not change while the server runs, or it can return an inconsistent result until restarted. Keep the fileWatcher facade description in the incremental-build skill reference in sync: the "off" mode, the inert subscription it returns, and that the memoized decision is now a mode string behind shouldUsePolling() and isWatchingDisabled().
da7da79 to
ed49fcc
Compare
d3xter666
left a comment
There was a problem hiding this comment.
The solution looks good and works as expected.
I would appreciate if someone can take another look, but apart the small comments in the tests, it LGTM
| t.is(server.serve.callCount, 1); | ||
| t.is(server.serve.getCall(0).args[1].liveReload, false, | ||
| "off wins over an explicit --live-reload"); |
There was a problem hiding this comment.
Maybe, in that case it would be good also to ensure/test that live-reload disabling logs an info message.
| t.is(server.serve.callCount, 1); | ||
| t.is(server.serve.getCall(0).args[1].liveReload, false, | ||
| "off wins over server.settings.liveReload"); |
There was a problem hiding this comment.
Like my previous comment. To me it seems that we must test here whether a log message for the liveReload override is displayed
| test.serial("subscribe: returns an inert subscription when UI5_WATCH_MODE=off", async (t) => { | ||
| // Disabled mode must not load any backend. The native stub stands in as a tripwire: if subscribe() | ||
| // delegated, it would be called. The returned subscription is real enough to track and unsubscribe. | ||
| process.env.UI5_WATCH_MODE = "off"; |
There was a problem hiding this comment.
Running this in an non isolated environment will set this to UI5_WATCH_MODE="off" and it might cause unexpected consequences.
Luckily, AVA creates subprocesses and we are kind of safe in that case, but it's worth pointing it.
Maybe it will be good if we set this for the sake of the test, but in the end to restore its original value, like we do here, for example: https://github.com/UI5/cli/blob/main/packages/cli/test/lib/dataDir.js#L27-L31
| }); | ||
|
|
||
| test.serial("isWatchingDisabled: true only for UI5_WATCH_MODE=off", async (t) => { | ||
| process.env.UI5_WATCH_MODE = "off"; |
There was a problem hiding this comment.
Like my previous comment here: https://github.com/UI5/cli/pull/1565/changes#r4105108570
This flag allows to disable file watching, e.g. in CI and other environments where sources do not change and the overhead (especially in polling mode) is unwanted.
JIRA: CPOUI5FOUNDATION-1355