perf(frontend): improve LCP with critical CSS inlining and async loading#255
Merged
perf(frontend): improve LCP with critical CSS inlining and async loading#255
Conversation
- Add inline critical CSS for immediate visual feedback (loading spinner) - Add asyncCssPlugin to convert stylesheet loading to non-blocking - Add dark mode support in inline critical CSS - Move favicon link after viewport meta for better resource prioritization Addresses: #227
There was a problem hiding this comment.
Pull request overview
This PR implements performance optimizations to improve Largest Contentful Paint (LCP) by introducing critical CSS inlining and async stylesheet loading. The changes enable instant visual feedback through a pre-rendered loading spinner while the full application loads.
Key Changes:
- Added inline critical CSS in
index.htmlwith loading spinner styles and dark mode support - Created
asyncCssPlugininvite.config.tsto convert blocking stylesheets to async loading via themedia="print"technique - Added pre-rendered loading spinner HTML to provide immediate visual feedback before React hydration
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
frontend/vite.config.ts |
Adds custom Vite plugin to transform stylesheet links for async loading using the print media trick |
frontend/index.html |
Adds inline critical CSS with loading spinner styles, reorders meta tags, and includes pre-rendered spinner HTML in root element |
- Add validation for href value before transformation - Skip links with existing media attribute to avoid duplicates - Use CSS variables aligned with Tailwind theme (gray-900, gray-50) - Fix misleading comment about JavaScript requirement
Contributor
This was referenced Dec 21, 2025
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Improves Largest Contentful Paint (LCP) by implementing critical CSS inlining and async stylesheet loading.
Closes #227
Changes
1. Critical CSS Inlining (
index.html)<style>block with minimal critical CSS:box-sizing,margin)PageLoadercomponentprefers-color-schememedia query2. Async CSS Loading (
vite.config.ts)asyncCssPluginVite plugin<link rel="stylesheet">to non-blocking async loadingmedia="print" onload="this.media='all'"technique3. Resource Prioritization
viewportmeta beforelinkelementsLCP Improvement Strategy
Technical Details
The async CSS technique:
media="print"prevents render-blocking (browser doesn't wait for print stylesheets)onloadswitches tomedia="all"when loaded, applying stylesTesting
npm run build- Successnpm run lint- PassCombined with PR #254
This PR works together with PR #254 (bundle optimization) which:
Together, these changes should significantly improve LCP from the baseline 9.4s.