From: Paul Donald Date: Wed, 24 Dec 2025 16:34:16 +0000 (+0100) Subject: luci-static: fix race condition when probing features X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;ds=sidebyside;p=project%2Fluci.git luci-static: fix race condition when probing features follow-up to a2fce95248a260d9471efbff94ad0cde7a90700d hasSystemFeature() inspects the cached result of probeSystemFeatures() which needs to have completed. Once all of the legacy (Lua) stuff is ready, this block runs: initDOM() { ... L.loaded = true; document.dispatchEvent(new CustomEvent('luci-loaded')); }, This commit now calls View.load() once system feature probing has completed, and LuCI itself has loaded. This ensures that the following load paradigm succeeds: return view.extend({ load() { return Promise.all([ ..., L.hasSystemFeature('x'), ]); }, ... The luci-loaded check prevents waiting when LuCI is already loaded (the common case after initial page load), but the listener handles the race condition where a View is instantiated before initDOM() completes. The flow: If L.loaded is true: initDOM() already ran --> skip waiting, proceed immediately. If L.loaded is false: initDOM() hasn't run yet --> add listener --> wait for it to complete. Signed-off-by: Paul Donald --- diff --git a/modules/luci-base/htdocs/luci-static/resources/luci.js b/modules/luci-base/htdocs/luci-static/resources/luci.js index 9f3b88302a..4925c03434 100644 --- a/modules/luci-base/htdocs/luci-static/resources/luci.js +++ b/modules/luci-base/htdocs/luci-static/resources/luci.js @@ -1899,16 +1899,14 @@ DOM.content(vp, E('div', { 'class': 'spinning' }, _('Loading view…'))); - return Promise.resolve(this.load()) - .then(function (...args) { - if (L.loaded) { - return Promise.resolve(...args); - } else { - return new Promise(function (resolve) { - document.addEventListener('luci-loaded', resolve.bind(null, ...args), { once: true }); - }); - } - }) + const ready = L.loaded + ? Promise.resolve() + : new Promise((resolve) => { + document.addEventListener('luci-loaded', resolve, { once: true }); + }); + + return ready + .then(LuCI.prototype.bind(this.load, this)) .then(LuCI.prototype.bind(this.render, this)) .then(LuCI.prototype.bind(function(nodes) { const vp = document.getElementById('view');