Visitar URL original
perf(core): cache CSS media query results until their inputs change by triniwiz · Pull Request #11505 · NativeScript/NativeScript · GitHub
Skip to content

perf(core): cache CSS media query results until their inputs change - #11505

Open
triniwiz wants to merge 2 commits into
mainfrom
perf/css-media-query-cache
Open

triniwiz wants to merge 2 commits into
mainfrom
perf/css-media-query-cache

Conversation

@triniwiz

@triniwiz triniwiz commented Oct 6, 2026 •

Copy link
Copy Markdown
Member

PR Checklist

What is the current behavior?

CSS matching evaluates every @media block for every view it matches. Each evaluation reads Screen.mainScreen width and height (on iOS, two native reads each), fetches the application orientation and appearance, and re-parses the query string. A stylesheet with media queries pays that once per view per query on every mount and restyle.

What is the new behavior?

Results are cached per query string. The inputs only change through the application, so the cache is cleared there, before CSS is re-applied:

  • setOrientation (which also refreshes screen metrics)
  • setSystemAppearance
  • syncTraitsFromWindow, which seeds the first window's traits without going through the setters

Clearing from event listeners would be too late: the application re-applies CSS before it raises orientationChanged and systemAppearanceChanged.

matchMedia() and MediaQueryList change events still evaluate their query directly. A cache epoch (getMediaQueryEpoch) lets other caches derived from query results notice a change; #11506 uses it.

The benchmark stylesheets have no @media rules, so this has no effect on the numbers in #11506, #11507 and #11510. The new spec shows the screen is read once per query until the cache is invalidated.

Part of a series: #11505 (this), #11506 (stacked on this one), #11507, #11510.

Every node matched against a stylesheet with @media blocks re-evaluated
each query: it read the screen size natively and re-parsed the query
string. Results are now cached per query string. The cache is cleared
where its inputs change (orientation, system appearance, and the first
window's traits), before CSS is re-applied, and a cache epoch lets
callers that derive data from query results notice the change.
@nx-cloud

nx-cloud Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit ef2411b

Command Status Duration Result
nx test apps-automated -c=android ✅ Succeeded 3m 18s View ↗
nx run-many --target=test --configuration=ci --... ✅ Succeeded <1s View ↗

💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗


☁️ Nx Cloud last updated this comment at 2026-10-06 23:02:53 UTC

@pkg-pr-new

pkg-pr-new Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@nativescript/core@11505
npm i https://pkg.pr.new/@nativescript/vite@11505
npm i https://pkg.pr.new/@nativescript/webpack@11505

commit: ef2411b

… changes

The screen size can change without an orientation or appearance change (a
foldable's display, a window moved to another screen), which left views
created afterwards matching against the old size. The cache now compares the
screen size once per turn and invalidates when it differs.
@NathanWalker

Copy link
Copy Markdown
Contributor

@triniwiz I pushed ef2411b on top of this branch. Here's the review finding it addresses, confirmed on an iPhone Duo simulator.

Gap: the cache was only invalidated on orientation and appearance changes. The screen size can change without either. Views created afterwards then matched @media width/height rules against the old size, while main evaluates them live.

Device check (iPhone Duo simulator in Bitrig): a toolbox probe page created a fresh .mq label every 1.5s, with @media (max-width: 600) { .mq { background-color: green } }.

  • In a rotatable app, every fold or unfold also flips portrait↔landscape (the cover display is tall, 466×678; the inner display is wide, 951×669). The orientation event fires and invalidates the cache, so there's no problem there.
  • In an app locked to portrait (common), the inner display comes up as 669×951 portrait. Folding and unfolding then change the size with no orientation event:
Portrait-locked, no orientation event Before ef2411b After
Unfold 466 → 669 new labels stay green ❌ (stale) —
Fold 669 → 466 — new labels turn green ✅

Fix: checkIfMediaQueryMatchesCached compares the screen size at most once per JS turn (two reads per turn instead of per query per view) and invalidates when it changed. This doesn't depend on any platform event, so it also covers external displays and secondary iPad windows. The spec gained a case that fails without it. Full suite passes, and the branch merges cleanly with current main.

Note: #11506 is stacked on the earlier commit of this branch and will need a rebase.

@NathanWalker NathanWalker added this to the 9.2 milestone Oct 6, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants