Skip to content

[2.x] perf: frontend performance improvements — preconnect hints, fetchpriority, FOUC fix, viewport#4561

Merged
imorland merged 1 commit into
2.xfrom
im/frontend-performance
Apr 12, 2026
Merged

[2.x] perf: frontend performance improvements — preconnect hints, fetchpriority, FOUC fix, viewport#4561
imorland merged 1 commit into
2.xfrom
im/frontend-performance

Conversation

@imorland

Copy link
Copy Markdown
Member

Summary

  • fetchpriority on preloads and logo images — JS preload hints get fetchpriority="low" so they don't compete with CSS and fonts. Forum and admin logo <img> tags get loading="eager" fetchpriority="high" decoding="async" as they are typically the LCP element.

  • sessionStorage CSS loading (FOUC fix) — On warm visits where CSS is already browser-cached, stylesheets are injected synchronously via JS before first paint, eliminating the flash of unstyled content. Cold visits use the existing async preload path and stamp sessionStorage keys on load. Stale keys from old CSS URLs are pruned automatically on each visit.

  • Automatic preconnect hintsDocument::makePreconnects() scans the page's CSS, JS, and preload URLs and emits <link rel="preconnect" crossorigin> + <link rel="dns-prefetch"> for any cross-origin origins. Explicit hints for FontAwesome CDN and Kit URLs are also added in FrontendServiceProvider.

  • Viewport meta fix — Removes maximum-scale=1, minimum-scale=1 from the viewport meta tag in Meta.php, basic.blade.php, and install/app.php. These attributes prevent user zoom on mobile, which is an accessibility issue. The initial-scale=1 is retained.

  • IE11 meta removed — The X-UA-Compatible meta tag has been removed from the installer; IE11 has been end-of-life since June 2022.

…rity, FOUC fix, viewport

- Add fetchpriority="low" to JS preload hints in FrontendServiceProvider
- Add loading="eager" fetchpriority="high" decoding="async" to forum and
  admin logo images in blade templates (LCP improvement)
- Add sessionStorage-based CSS loading: warm visits inject stylesheets
  synchronously before first paint to eliminate FOUC; cold visits use
  async preload path and set sessionStorage keys on load; stale keys
  from old URLs are pruned automatically
- Add Document::makePreconnects() to auto-generate preconnect and
  dns-prefetch hints for any cross-origin CSS, JS, or preload URLs
- Add explicit preconnect hints for FontAwesome CDN and Kit URLs in
  FrontendServiceProvider
- Remove maximum-scale=1 and minimum-scale=1 from viewport meta in
  Meta.php, basic.blade.php, and install/app.php (accessibility: allows
  user zoom on mobile)
- Remove IE11 X-UA-Compatible meta from installer
@imorland imorland changed the title perf: frontend performance improvements — preconnect hints, fetchpriority, FOUC fix, viewport [2.x] perf: frontend performance improvements — preconnect hints, fetchpriority, FOUC fix, viewport Apr 12, 2026
@imorland imorland added this to the 2.0.0-rc.1 milestone Apr 12, 2026
@imorland imorland marked this pull request as ready for review April 12, 2026 10:51
@imorland imorland requested a review from a team as a code owner April 12, 2026 10:51
@imorland imorland merged commit 874aeb7 into 2.x Apr 12, 2026
25 checks passed
@imorland imorland deleted the im/frontend-performance branch April 12, 2026 10:52
ekumanov added a commit to ekumanov/framework that referenced this pull request Apr 19, 2026
…n iOS Safari

iOS Safari silently drops programmatic scrollTop writes while a momentum
(inertial) scroll is in flight, which causes PostStream to visibly jump when
loadPrevious() prepends older posts during a flick scroll upward. Routing the
restore through `window.scrollTo(x, y)` instead of jQuery's `$window.scrollTop(y)`
goes through a different WebKit code path that halts the in-flight momentum and
applies the new position, fixing the jump without side effects on other platforms.

This behavior was unmasked by flarum#4561 (viewport meta change): on beta.8 the viewport
included `maximum-scale=1, minimum-scale=1`, which put iOS in a simpler scroll
pipeline where scrollTop writes typically landed; once user-zoom is allowed the
zoom/scroll coordination layer starts dropping those writes.

Fixes flarum#4587.
imorland added a commit that referenced this pull request May 14, 2026
…lesheet (#4664)

The dual-path strategy from #4561 (sessionStorage warm cache + async
preload cold path) relied on JS-injected <link rel="stylesheet"> elements
blocking paint, which they do not by spec. The result was a flash of
unstyled content on cross-origin asset hosts (S3 / CloudFront most
visibly), on every cold tab, and intermittently on warm visits too.

- makeHead() now emits a standard <link rel="stylesheet"> for forum/admin
  CSS. Parser-discovered, render-blocking, ~single-digit ms on a CDN.
- The sessionStorage warm-path script and the noscript fallback are
  removed; the inline critical CSS stays as a safety net so the body
  has a theme-accurate background while the stylesheet is in flight.
- JS preloads switch from fetchpriority="low" to "high" — now that the
  stylesheet blocks paint, the SPA boot is the next critical-path item.
- New Document::$preHead bucket for content that must render before the
  stylesheet (used by the inline data-theme script so dark-mode users
  never see a light-flash if the browser paints before CSS arrives).
  Document::$head[] semantics are unchanged: items still render after
  the stylesheet, so admin-supplied <style>/<link> overrides correctly
  win the cascade.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant