You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Selector cache hit rate falls from 100% to 0% at CACHE_LIMIT + 1 under jsdom's stylesheet scan (2.2.25+); #185/#186 are not in master #242
Since 2.2.25 the compiled-selector caches are a strict LRU bounded at CACHE_LIMIT = 1000 (2.2.28 src/nwsapi.js:236, eviction at :290). jsdom's getComputedStyle matches every stylesheet rule against each element in sheet order, which is a loop. On a loop of N > limit selectors, LRU always evicts the one the scan needs next, so the hit rate drops from 100% to 0% at N = limit + 1 and every match recompiles. A page carrying antd's CSS-in-JS has about 2,300 rules. One of our jsdom test files went from 3.7 s on 2.2.22 to a 37 s timeout on 2.2.28, with about 1.05M recompiles. With the limit raised to 1e6 it runs in 6.8 s.
Reproducer (npm i jsdom nwsapi@2.2.28):
const{JSDOM}=require('jsdom'),nwsapi=require('nwsapi');for(constNof[1000,1001]){const{ window }=newJSDOM('<p class="c0">'),el=window.document.querySelector('p');constnw=nwsapi({document: window.document,DOMException: window.DOMException});constsels=Array.from({length: N},(_,i)=>`.c${i}`);sels.forEach(s=>nw.match(s,el));// first pass compiles each selector onceletmiss=0;for(letpass=0;pass<10;pass++)for(constsofsels){miss+=!nw.matchResolvers.has(s);nw.match(s,el);}console.log(`${N} selectors: ${miss} cache misses in ${N*10} matches`);}
Output: 1000 selectors: 0 cache misses in 10000 matches, then 1001 selectors: 10010 cache misses in 10010 matches.
#185 (two-generation eviction) and #186 (limit 4096) were merged on 2026-09-07, but neither merge commit is in current master or in 2.2.28. Master (8b622b5) also adds CACHE_BYTES = 2 MB, which evicts from the same head. Even with the entry limit at 100,000, selectors shaped like :where(.css-x).ant-btn-N:not(:disabled):not(.ant-btn-disabled):hover miss on every match from N = 1,254.
Could the next 2.2.x (a) restore bounds that cover a real stylesheet, or let the host set them (jsdom already calls configure(), which accepts only booleans today), and (b) evict so that a scan larger than the cache keeps a resident subset hitting instead of none?
@davidwilder
thank you for the review of this functionality (now forgotten/missed).
The only reason that pushed us using a different approach for the size of the cache instead of mixing it in a series of flags to enable/disable features. A number representing the configurable size of the cached resolvers was a reasoned pick that I would hope to still yield what were the original expectations from the configure method initialization.
Haven't implemented it completely yet but the idea was to make the last arguments of configure would represent a Number().
I am open to alternative suggestions to get the same functionality (as in configure) and covering the obvious needs depicted above.
Activity
dperini commentedon Oct 8, 2026
@davidwilder
thank you for the review of this functionality (now forgotten/missed).
The only reason that pushed us using a different approach for the size of the cache instead of mixing it in a series of flags to enable/disable features. A number representing the configurable size of the cached resolvers was a reasoned pick that I would hope to still yield what were the original expectations from the
configuremethod initialization.Haven't implemented it completely yet but the idea was to make the last arguments of
configurewould represent a Number().I am open to alternative suggestions to get the same functionality (as in
configure) and covering the obvious needs depicted above.dperini commentedon Oct 10, 2026
@davidwilder
can you please check if the changes in #243 satisfy the expressed needs.
Thanks @jdalton for the quick fix.
jdalton commentedon Oct 11, 2026
V3 retains useful compiled plans during oversized scans and supports configurable cache budgets. See Selector caching.
#246 brings the admission policy to V2, following the configurable limits in #243.
chore: pin nwsapi so the a11y suite stops timing out in the no-lock c…
chore: pin nwsapi so the a11y suite stops timing out in the no-lock c…